├── nuget ├── package.bat └── nuget.exe ├── logo.png ├── src ├── SimpleValidator │ ├── Interfaces │ │ └── IRule.cs │ ├── Messages │ │ ├── LanguageCodes.cs │ │ ├── MessageContainer.cs │ │ └── MessageFactory.cs │ ├── Exceptions │ │ └── ValidationException.cs │ ├── Results │ │ ├── ValidationError.cs │ │ └── ValidationMethodResult.cs │ ├── SimpleValidator.nuspec │ ├── Validator.Numbers.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── SimpleValidator.csproj │ ├── Validator.cs │ ├── Validator.Strings.cs │ ├── Validator.Dates.cs │ └── Extensions │ │ └── ExtensionMethods.cs ├── SimpleValidator.Tests │ ├── Validator_Is_Tests.cs │ ├── Validator_Init_Tests.cs │ ├── Extensions_IsNotNull_Tests.cs │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── Validator_IsNotNull_Tests.cs │ ├── Validator_IsMatch_Tests.cs │ ├── Validator_IsEmail_Tests.cs │ ├── Extensions_Is_Tests.cs │ ├── Validator_IsMinLength_Tests.cs │ ├── Validator_Date_Tests.cs │ ├── SimpleValidator.Tests.csproj │ ├── Extensions_Tests.cs │ └── Resources │ │ └── input.txt └── SimpleValidator.sln ├── .gitignore └── README.md /nuget/package.bat: -------------------------------------------------------------------------------- 1 | nuget pack ../src/SimpleValidator/SimpleValidator.csproj -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnpretorius/simple-validator/HEAD/logo.png -------------------------------------------------------------------------------- /nuget/nuget.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnpretorius/simple-validator/HEAD/nuget/nuget.exe -------------------------------------------------------------------------------- /src/SimpleValidator/Interfaces/IRule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace SimpleValidator.Interfaces 7 | { 8 | public interface IRule 9 | { 10 | bool IsValid(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/SimpleValidator/Messages/LanguageCodes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace SimpleValidator.Messages 7 | { 8 | /// 9 | /// To support more translations, simply add more translations to this enum and provide the implementation in the factory method 10 | /// 11 | public enum LanguageCodes 12 | { 13 | en_GB 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/SimpleValidator/Exceptions/ValidationException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace SimpleValidator.Exceptions 7 | { 8 | public class ValidationException : Exception 9 | { 10 | public Validator Validator; 11 | 12 | private ValidationException() 13 | { 14 | } 15 | 16 | public ValidationException(Validator validator) : base() 17 | { 18 | Validator = validator; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/SimpleValidator.Tests/Validator_Is_Tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SimpleValidator; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using System.Collections.Generic; 5 | using SimpleValidator.Extensions; 6 | 7 | namespace SimpleValidator.Tests 8 | { 9 | [TestClass] 10 | public class Validator_Is_Tests 11 | { 12 | [TestMethod] 13 | public void IsGreaterThanTest() 14 | { 15 | Validator validator = new Validator(); 16 | 17 | validator.Is(() => 5.IsGreaterThan(1)); 18 | 19 | Assert.IsTrue(validator.Errors.Count == 0); 20 | } 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/SimpleValidator/Results/ValidationError.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace SimpleValidator.Results 7 | { 8 | public class ValidationError 9 | { 10 | public ValidationError() 11 | { 12 | Name = ""; 13 | Message = ""; 14 | } 15 | 16 | public string Name { get; set; } 17 | public string Message { get; set; } 18 | 19 | #region " Helpers " 20 | 21 | public static ValidationError Create(string name, string message) 22 | { 23 | ValidationError error = new ValidationError() 24 | { 25 | Name = name, 26 | Message = message 27 | }; 28 | 29 | return error; 30 | } 31 | 32 | #endregion 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/SimpleValidator.Tests/Validator_Init_Tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SimpleValidator; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using System.Collections.Generic; 5 | 6 | namespace SimpleValidator.Tests 7 | { 8 | [TestClass] 9 | public class Validator_Init_Tests 10 | { 11 | [TestMethod] 12 | public void Test_Object_Creation() 13 | { 14 | Validator val = new Validator(); 15 | 16 | Assert.IsNotNull(val); 17 | Assert.IsNotNull(val.Errors); 18 | Assert.IsTrue(val.Errors.Count == 0); 19 | } 20 | 21 | [TestMethod] 22 | public void Test_Error_Message_Returns() 23 | { 24 | Validator val = new Validator(); 25 | val.IsMatch("abc", "abc").WithMessage("This is a message"); 26 | Assert.IsNotNull(val.Errors.Count == 0); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/SimpleValidator/SimpleValidator.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $id$ 5 | $version$ 6 | Gordon Pretorius 7 | Gordon Pretorius 8 | https://opensource.org/licenses/MIT 9 | https://github.com/gnpretorius/simple-validator 10 | https://cloud.githubusercontent.com/assets/3989178/11175818/537a7430-8c2e-11e5-8d97-b136d8f7aa78.png 11 | false 12 | $description$ 13 | Latest version. Getting to a stage where I will make it a 1.0 release. This might contain some breaking changes. 14 | Copyright 2015 15 | Validation Net BusinessRule Validator TypeChecking 16 | 17 | -------------------------------------------------------------------------------- /src/SimpleValidator/Validator.Numbers.cs: -------------------------------------------------------------------------------- 1 | using SimpleValidator.Extensions; 2 | using SimpleValidator.Results; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Globalization; 6 | using System.Linq; 7 | using System.Linq.Expressions; 8 | using System.Text; 9 | 10 | namespace SimpleValidator 11 | { 12 | public partial class Validator 13 | { 14 | #region " IsNotZero " 15 | 16 | public Validator IsNotZero(int value) 17 | { 18 | return IsNotZero("", value); 19 | } 20 | 21 | public Validator IsNotZero(string name, int value) 22 | { 23 | return IsNotZero(name, value, string.Format(MessageContainer.IsNotZeroMessage, name)); 24 | } 25 | 26 | public Validator IsNotZero(string name, int value, string message) 27 | { 28 | // do the check 29 | if (value.IsNotZero()) 30 | { 31 | return NoError(); 32 | } 33 | else 34 | { 35 | return AddError(name, message); 36 | } 37 | } 38 | 39 | #endregion 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/SimpleValidator.Tests/Extensions_IsNotNull_Tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SimpleValidator; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using System.Collections.Generic; 5 | using SimpleValidator.Extensions; 6 | 7 | namespace SimpleValidator.Tests 8 | { 9 | [TestClass] 10 | public class Extensions_IsNotNull_Tests 11 | { 12 | #region " Helpers " 13 | 14 | public static List GetTestObjects() 15 | { 16 | List objects = new List(); 17 | 18 | objects.Add(null); 19 | objects.Add(string.Empty); 20 | objects.Add(""); 21 | objects.Add(Guid.NewGuid()); 22 | objects.Add(true); 23 | objects.Add("null"); 24 | 25 | return objects; 26 | } 27 | 28 | #endregion 29 | 30 | [TestMethod] 31 | public void Test_IsNotNull() 32 | { 33 | List objects = GetTestObjects(); 34 | 35 | Assert.IsFalse(objects[0].IsNotNull()); 36 | Assert.IsTrue(objects[1].IsNotNull()); 37 | Assert.IsTrue(objects[2].IsNotNull()); 38 | Assert.IsTrue(objects[3].IsNotNull()); 39 | Assert.IsTrue(objects[4].IsNotNull()); 40 | Assert.IsTrue(objects[5].IsNotNull()); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/SimpleValidator.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SimpleValidator.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SimpleValidator.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("07d6eab6-163e-4cdf-a274-359911edb7a9")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/SimpleValidator.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleValidator", "SimpleValidator\SimpleValidator.csproj", "{ECE65351-BDA1-476B-8434-561753F0A0C7}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleValidator.Tests", "SimpleValidator.Tests\SimpleValidator.Tests.csproj", "{B7E2D22E-1395-4DBB-84C8-605B119B7588}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {ECE65351-BDA1-476B-8434-561753F0A0C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {ECE65351-BDA1-476B-8434-561753F0A0C7}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {ECE65351-BDA1-476B-8434-561753F0A0C7}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {ECE65351-BDA1-476B-8434-561753F0A0C7}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {B7E2D22E-1395-4DBB-84C8-605B119B7588}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {B7E2D22E-1395-4DBB-84C8-605B119B7588}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {B7E2D22E-1395-4DBB-84C8-605B119B7588}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {B7E2D22E-1395-4DBB-84C8-605B119B7588}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /src/SimpleValidator/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SimpleValidator")] 9 | [assembly: AssemblyDescription("A simple validation library for .Net")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SimpleValidator")] 13 | [assembly: AssemblyCopyright("Copyright Gordon Pretorius © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("769b019d-a718-4f91-b6ca-bc0bf84ab7d1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("0.6.1.0")] 36 | [assembly: AssemblyFileVersion("0.6.1.0")] 37 | -------------------------------------------------------------------------------- /src/SimpleValidator/Messages/MessageContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace SimpleValidator.Messages 7 | { 8 | public class MessageContainer 9 | { 10 | public string IsNotNullMessage { get; set; } 11 | public string IsNotNullOrEmptyMessage { get; set; } 12 | public string IsNotNullOrWhiteSpaceMessage { get; set; } 13 | public string IsNotZeroMessage { get; set; } 14 | public string IsPasswordMessage { get; set; } 15 | public string IsMinLengthMessage { get; set; } 16 | public string IsMaxLengthMessage { get; set; } 17 | public string IsExactLengthMessage { get; set; } 18 | public string IsBetweenLengthMessage { get; set; } 19 | public string IsMessage { get; set; } 20 | public string IsNotMessage { get; set; } 21 | public string IsEmailMessage { get; set; } 22 | public string IsRegexMessage { get; set; } 23 | public string IsMatchMessage { get; set; } 24 | public string IsDateMessage { get; set; } 25 | public string IsRuleMessage { get; set; } 26 | 27 | #region " Dates " 28 | 29 | public string IsGreaterThanMessage { get; set; } 30 | public string IsGreaterThanOrEqualToMessage { get; set; } 31 | public string IsLessThanMessage { get; set; } 32 | public string IsLessThanOrEqualToMessage { get; set; } 33 | public string IsEqualToMessage { get; set; } 34 | public string IsBetweenInclusiveMessage { get; set; } 35 | public string IsBetweenExclusiveMessage { get; set; } 36 | 37 | #endregion 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/SimpleValidator/Results/ValidationMethodResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace SimpleValidator.Results 7 | { 8 | public class ValidationMethodResult 9 | { 10 | #region " Constructor " 11 | 12 | public ValidationMethodResult() 13 | { 14 | } 15 | 16 | public ValidationMethodResult(T result) 17 | : this() 18 | { 19 | Result = result; 20 | } 21 | 22 | public ValidationMethodResult(Validator validator) 23 | : this() 24 | { 25 | Validator = validator; 26 | } 27 | 28 | public ValidationMethodResult(Validator validator, T result) 29 | : this() 30 | { 31 | Validator = validator; 32 | Result = result; 33 | } 34 | 35 | #endregion 36 | 37 | #region " Properties " 38 | 39 | public T Result { get; set; } 40 | public Validator Validator; 41 | 42 | public bool IsValid 43 | { 44 | get 45 | { 46 | if (Validator == null) 47 | { 48 | return true; 49 | } 50 | 51 | return Validator.IsValid; 52 | } 53 | } 54 | 55 | public List Errors 56 | { 57 | get 58 | { 59 | if (Validator == null) 60 | { 61 | return new List(); 62 | } 63 | 64 | return Validator.Errors; 65 | } 66 | } 67 | 68 | public List UniqueErrors 69 | { 70 | get 71 | { 72 | if (Validator == null) 73 | { 74 | return new List(); 75 | } 76 | 77 | return Validator.UniqueErrors; 78 | } 79 | } 80 | 81 | #endregion 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/SimpleValidator.Tests/Validator_IsNotNull_Tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SimpleValidator; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using System.Collections.Generic; 5 | using SimpleValidator.Extensions; 6 | 7 | namespace SimpleValidator.Tests 8 | { 9 | [TestClass] 10 | public class Validator_IsNotNull_Tests 11 | { 12 | #region " Helpers " 13 | 14 | public static List GetTestObjects() 15 | { 16 | List objects = new List(); 17 | 18 | objects.Add(null); 19 | objects.Add(string.Empty); 20 | objects.Add(""); 21 | objects.Add(Guid.NewGuid()); 22 | objects.Add(true); 23 | objects.Add("null"); 24 | 25 | return objects; 26 | } 27 | 28 | #endregion 29 | 30 | [TestMethod] 31 | public void Test_IsNotNull() 32 | { 33 | Validator validator = new Validator(); 34 | 35 | foreach (var obj in GetTestObjects()) 36 | { 37 | validator.IsNotNull(obj); 38 | } 39 | 40 | Assert.IsTrue(validator.Errors.Count == 1); 41 | } 42 | 43 | [TestMethod] 44 | public void Test_IsNotNull_With_Name() 45 | { 46 | Validator validator = new Validator(); 47 | 48 | foreach (var obj in GetTestObjects()) 49 | { 50 | validator.IsNotNull("Object", obj); 51 | } 52 | 53 | Assert.IsTrue(validator.Errors.Count == 1); 54 | Assert.IsTrue(validator.Errors[0].Name == "Object"); 55 | } 56 | 57 | [TestMethod] 58 | public void Test_IsNotNull_With_Name_Message() 59 | { 60 | Validator validator = new Validator(); 61 | 62 | foreach (var obj in GetTestObjects()) 63 | { 64 | validator.IsNotNull("Object", obj, "Error"); 65 | } 66 | 67 | Assert.IsTrue(validator.Errors.Count == 1); 68 | Assert.IsTrue(validator.Errors[0].Name == "Object"); 69 | Assert.IsTrue(validator.Errors[0].Message == "Error"); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/SimpleValidator.Tests/Validator_IsMatch_Tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SimpleValidator; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using System.Collections.Generic; 5 | 6 | namespace SimpleValidator.Tests 7 | { 8 | [TestClass] 9 | public class Validator_IsMatch_Tests 10 | { 11 | [TestMethod] 12 | public void Test_Matches() 13 | { 14 | string input = "abc123"; 15 | 16 | Validator validator = new Validator(); 17 | 18 | validator.IsMatch(input, ""); 19 | validator.IsMatch(input, "a"); 20 | validator.IsMatch(input, "ab"); 21 | validator.IsMatch(input, "abc"); 22 | validator.IsMatch(input, "1"); 23 | validator.IsMatch(input, "12"); 24 | validator.IsMatch(input, "123"); 25 | validator.IsMatch(input, "abc123"); 26 | validator.IsMatch(input, "Abc123"); 27 | validator.IsMatch(input, "aBc123"); 28 | validator.IsMatch(input, "abC123"); 29 | validator.IsMatch(input, "abc123 "); 30 | validator.IsMatch(input, " abc123"); 31 | validator.IsMatch(input, null); 32 | validator.IsMatch(input, "****"); 33 | 34 | Assert.IsTrue(validator.Errors.Count == 14); 35 | } 36 | 37 | [TestMethod] 38 | public void Test_Inputs() 39 | { 40 | string match = "abc123"; 41 | 42 | Validator validator = new Validator(); 43 | 44 | validator.IsMatch("", match); 45 | validator.IsMatch("a", match); 46 | validator.IsMatch("ab", match); 47 | validator.IsMatch("abc", match); 48 | validator.IsMatch("1", match); 49 | validator.IsMatch("12", match); 50 | validator.IsMatch("123", match); 51 | validator.IsMatch("abc123", match); 52 | validator.IsMatch("Abc123", match); 53 | validator.IsMatch("aBc123", match); 54 | validator.IsMatch("abC123", match); 55 | validator.IsMatch("abc123 ", match); 56 | validator.IsMatch(" abc123", match); 57 | validator.IsMatch(null, match); 58 | validator.IsMatch("****", match); 59 | 60 | Assert.IsTrue(validator.Errors.Count == 14); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/SimpleValidator.Tests/Validator_IsEmail_Tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SimpleValidator; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using System.Collections.Generic; 5 | using System.Net; 6 | using SimpleValidator.Exceptions; 7 | using SimpleValidator.Extensions; 8 | 9 | namespace SimpleValidator.Tests 10 | { 11 | [TestClass] 12 | public class Validator_IsEmail_Tests 13 | { 14 | [TestMethod] 15 | public void Test_Invalid_Email() 16 | { 17 | 18 | string email = "InvalidEmail"; 19 | 20 | Validator validator = new Validator(); 21 | 22 | validator.IsEmail(email); 23 | 24 | System.Diagnostics.Debug.WriteLine(validator.Errors.Count); 25 | 26 | Assert.IsTrue(validator.Errors.Count == 1); 27 | } 28 | 29 | [TestMethod] 30 | public void Test_Invalid_Emails() 31 | { 32 | List emails = new List() 33 | { 34 | "valid@test.com", // valid 35 | "valid@t.com", // valid 36 | "v@v.co", // valid 37 | "@v.com", // invalid 38 | "v@.co", // invalid 39 | "v@v" // invalid 40 | }; 41 | 42 | Validator validator = new Validator(); 43 | 44 | foreach (var email in emails) 45 | { 46 | validator.IsEmail(email); 47 | } 48 | 49 | Assert.IsTrue(validator.Errors.Count == 3); 50 | } 51 | 52 | [TestMethod] 53 | public void Test_Email_Message() 54 | { 55 | string email = "InvalidEmail"; 56 | 57 | Validator validator = new Validator(); 58 | 59 | validator.IsEmail(email).WithMessage("Test message"); 60 | 61 | Assert.AreEqual(validator.Errors[0].Message, "Test message"); 62 | } 63 | 64 | [TestMethod] 65 | public void Test_Multiple_Email_Message() 66 | { 67 | List emails = new List() 68 | { 69 | "v@v.co", // valid 70 | "@v.com", // invalid 71 | "valid@t.com", // valid 72 | "v@.co", // invalid 73 | "valid@test.com", // valid 74 | "v@v" // invalid 75 | }; 76 | 77 | Validator validator = new Validator(); 78 | 79 | for (int i = 0; i < emails.Count; i++) 80 | { 81 | validator.IsEmail(emails[i]).WithMessage("Message " + i); 82 | } 83 | 84 | Assert.IsTrue(validator.Errors.Count == 3); 85 | Assert.AreEqual(validator.Errors[0].Message, "Message 1"); 86 | Assert.AreEqual(validator.Errors[1].Message, "Message 3"); 87 | Assert.AreEqual(validator.Errors[2].Message, "Message 5"); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/SimpleValidator.Tests/Extensions_Is_Tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SimpleValidator; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using Microsoft.Win32; 7 | using SimpleValidator.Extensions; 8 | using SimpleValidator.Results; 9 | 10 | namespace SimpleValidator.Tests 11 | { 12 | [TestClass] 13 | public class Extensions_Is_Tests 14 | { 15 | public static List GetTestData() 16 | { 17 | return new List() 18 | { 19 | "", 20 | "a", 21 | "abc", 22 | "1", 23 | "0", 24 | "1.1", 25 | "1.1.1", 26 | "1000000000000", 27 | "0.000000001", 28 | "true", 29 | "True", 30 | "False", 31 | "false", 32 | "blah blah", 33 | " ", 34 | " ", 35 | "0.9999", 36 | "123", 37 | "-234" 38 | }; 39 | } 40 | 41 | [TestMethod] 42 | public void Test_IsInt() 43 | { 44 | int pass = GetTestData().Count(input => input.IsInt()); 45 | 46 | Assert.IsTrue(pass == 4); 47 | } 48 | 49 | [TestMethod] 50 | public void Test_IsShort() 51 | { 52 | int pass = GetTestData().Count(input => input.IsShort()); 53 | 54 | Assert.IsTrue(pass == 4); 55 | } 56 | 57 | [TestMethod] 58 | public void Test_IsLong() 59 | { 60 | int pass = GetTestData().Count(input => input.IsLong()); 61 | 62 | Assert.IsTrue(pass == 5); 63 | } 64 | 65 | [TestMethod] 66 | public void Test_IsDouble() 67 | { 68 | int pass = GetTestData().Count(input => input.IsDouble()); 69 | 70 | Assert.IsTrue(pass == 8); 71 | } 72 | 73 | [TestMethod] 74 | public void Test_IsDecimal() 75 | { 76 | int pass = GetTestData().Count(input => input.IsDecimal()); 77 | 78 | Assert.IsTrue(pass == 8); 79 | } 80 | 81 | [TestMethod] 82 | public void Test_IsBool() 83 | { 84 | int pass = GetTestData().Count(input => input.IsBool()); 85 | 86 | Assert.IsTrue(pass == 4); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/SimpleValidator/SimpleValidator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {ECE65351-BDA1-476B-8434-561753F0A0C7} 8 | Library 9 | Properties 10 | SimpleValidator 11 | SimpleValidator 12 | v4.0 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 67 | -------------------------------------------------------------------------------- /src/SimpleValidator/Messages/MessageFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace SimpleValidator.Messages 7 | { 8 | public class MessageFactory 9 | { 10 | private MessageFactory() 11 | { 12 | } 13 | 14 | /// 15 | /// Provides the default language instance of the messages 16 | /// 17 | /// 18 | public static MessageContainer Create() 19 | { 20 | return Create(LanguageCodes.en_GB); 21 | } 22 | 23 | public static MessageContainer Create(LanguageCodes code) 24 | { 25 | switch (code) 26 | { 27 | case LanguageCodes.en_GB: 28 | return new MessageContainer() 29 | { 30 | IsNotNullMessage = "'{0}' cannot be null.", 31 | IsNotNullOrEmptyMessage = "'{0}' cannot be null or empty.", 32 | IsNotNullOrWhiteSpaceMessage = "'{0}' cannot be null or whitespace only.", 33 | IsNotZeroMessage = "'{0}' cannot be zero.", 34 | IsPasswordMessage = "'{0}' is not a valid password. Passwords must be 8 to 30 characters, at least on 1 uppercase letter, at least 1 lowercase letter and at least one number.", 35 | IsMinLengthMessage = "'{0}' must be a at least {1} characters.", 36 | IsMaxLengthMessage = "'{0}' must be {1} characters or less.", 37 | IsExactLengthMessage = "'{0}' must be exactly {1} characters.", 38 | IsBetweenLengthMessage = "'{0}' must be at least {1} and at most {2} characters.", 39 | IsMessage = "'{0}' does not match the specified criteria.", 40 | IsNotMessage = "'{0}' does not match the specified criteria.", 41 | IsEmailMessage = "'{0}' is not a valid email address.", 42 | IsRegexMessage = "'{0}' does not match the provided regular expression.", 43 | IsMatchMessage = "'{0}' did not match the specified criteria.", 44 | IsDateMessage = "'{0}' is not a valid date.", 45 | IsRuleMessage = "'{0}' failed the provided business rule provided.", 46 | 47 | // Dates 48 | IsGreaterThanMessage = "'{0}' must be greater than '{1}'.", 49 | IsGreaterThanOrEqualToMessage = "'{0}' must be greater than or equal to '{1}'.", 50 | IsLessThanMessage = "'{0}' must be less than '{1}'.", 51 | IsLessThanOrEqualToMessage = "'{0}' must be less than or equal to '{1}'.", 52 | IsEqualToMessage = "'{0}' must be equal to '{1}'.", 53 | IsBetweenInclusiveMessage = "'{0}' must be between '{1}' and '{2}' (inclusive).", 54 | IsBetweenExclusiveMessage = "'{0}' must be between '{1}' and '{2}' (exclusive)." 55 | }; 56 | 57 | default: 58 | return Create(LanguageCodes.en_GB); 59 | } 60 | 61 | 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | [Rr]eleases/ 14 | x64/ 15 | x86/ 16 | build/ 17 | bld/ 18 | [Bb]in/ 19 | [Oo]bj/ 20 | 21 | # Roslyn cache directories 22 | *.ide/ 23 | 24 | # MSTest test Results 25 | [Tt]est[Rr]esult*/ 26 | [Bb]uild[Ll]og.* 27 | 28 | #NUNIT 29 | *.VisualState.xml 30 | TestResult.xml 31 | 32 | # Build Results of an ATL Project 33 | [Dd]ebugPS/ 34 | [Rr]eleasePS/ 35 | dlldata.c 36 | 37 | *_i.c 38 | *_p.c 39 | *_i.h 40 | *.ilk 41 | *.meta 42 | *.obj 43 | *.pch 44 | *.pdb 45 | *.pgc 46 | *.pgd 47 | *.rsp 48 | *.sbr 49 | *.tlb 50 | *.tli 51 | *.tlh 52 | *.tmp 53 | *.tmp_proj 54 | *.log 55 | *.vspscc 56 | *.vssscc 57 | .builds 58 | *.pidb 59 | *.svclog 60 | *.scc 61 | 62 | # Chutzpah Test files 63 | _Chutzpah* 64 | 65 | # Visual C++ cache files 66 | ipch/ 67 | *.aps 68 | *.ncb 69 | *.opensdf 70 | *.sdf 71 | *.cachefile 72 | 73 | # Visual Studio profiler 74 | *.psess 75 | *.vsp 76 | *.vspx 77 | 78 | # TFS 2012 Local Workspace 79 | $tf/ 80 | 81 | # Guidance Automation Toolkit 82 | *.gpState 83 | 84 | # ReSharper is a .NET coding add-in 85 | _ReSharper*/ 86 | *.[Rr]e[Ss]harper 87 | *.DotSettings.user 88 | 89 | # JustCode is a .NET coding addin-in 90 | .JustCode 91 | 92 | # TeamCity is a build add-in 93 | _TeamCity* 94 | 95 | # DotCover is a Code Coverage Tool 96 | *.dotCover 97 | 98 | # NCrunch 99 | _NCrunch_* 100 | .*crunch*.local.xml 101 | 102 | # MightyMoose 103 | *.mm.* 104 | AutoTest.Net/ 105 | 106 | # Web workbench (sass) 107 | .sass-cache/ 108 | 109 | # Installshield output folder 110 | [Ee]xpress/ 111 | 112 | # DocProject is a documentation generator add-in 113 | DocProject/buildhelp/ 114 | DocProject/Help/*.HxT 115 | DocProject/Help/*.HxC 116 | DocProject/Help/*.hhc 117 | DocProject/Help/*.hhk 118 | DocProject/Help/*.hhp 119 | DocProject/Help/Html2 120 | DocProject/Help/html 121 | 122 | # Click-Once directory 123 | publish/ 124 | 125 | # Publish Web Output 126 | *.[Pp]ublish.xml 127 | *.azurePubxml 128 | # TODO: Comment the next line if you want to checkin your web deploy settings 129 | # but database connection strings (with potential passwords) will be unencrypted 130 | *.pubxml 131 | *.publishproj 132 | 133 | # NuGet Packages 134 | *.nupkg 135 | # The packages folder can be ignored because of Package Restore 136 | **/packages/* 137 | # except build/, which is used as an MSBuild target. 138 | !**/packages/build/ 139 | # If using the old MSBuild-Integrated Package Restore, uncomment this: 140 | #!**/packages/repositories.config 141 | 142 | # Windows Azure Build Output 143 | csx/ 144 | *.build.csdef 145 | 146 | # Windows Store app package directory 147 | AppPackages/ 148 | 149 | # Others 150 | sql/ 151 | *.Cache 152 | ClientBin/ 153 | [Ss]tyle[Cc]op.* 154 | ~$* 155 | *~ 156 | *.dbmdl 157 | *.dbproj.schemaview 158 | *.pfx 159 | *.publishsettings 160 | node_modules/ 161 | 162 | # RIA/Silverlight projects 163 | Generated_Code/ 164 | 165 | # Backup & report files from converting an old project file 166 | # to a newer Visual Studio version. Backup files are not needed, 167 | # because we have git ;-) 168 | _UpgradeReport_Files/ 169 | Backup*/ 170 | UpgradeLog*.XML 171 | UpgradeLog*.htm 172 | 173 | # SQL Server files 174 | *.mdf 175 | *.ldf 176 | 177 | # Business Intelligence projects 178 | *.rdl.data 179 | *.bim.layout 180 | *.bim_*.settings 181 | 182 | # Microsoft Fakes 183 | FakesAssemblies/ 184 | -------------------------------------------------------------------------------- /src/SimpleValidator.Tests/Validator_IsMinLength_Tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using SimpleValidator; 4 | 5 | namespace SimpleValidator.Tests 6 | { 7 | [TestClass] 8 | public class Validator_IsMinLength_Tests 9 | { 10 | [TestMethod] 11 | public void Test_IsMinLength() 12 | { 13 | string input = "12345"; 14 | 15 | Validator validator = new Validator(); 16 | 17 | validator.IsMinLength(input, 1); 18 | validator.IsMinLength(input, 2); 19 | validator.IsMinLength(input, 3); 20 | validator.IsMinLength(input, 4); 21 | validator.IsMinLength(input, 5); 22 | validator.IsMinLength(input, 6); 23 | validator.IsMinLength(input, 7); 24 | 25 | Assert.IsTrue(validator.Errors.Count == 2); 26 | } 27 | 28 | [TestMethod] 29 | public void Test_IsMinLength_Null() 30 | { 31 | string input = null; 32 | 33 | Validator validator = new Validator(); 34 | 35 | validator.IsMinLength(input, 1); 36 | validator.IsMinLength(input, 2); 37 | validator.IsMinLength(input, 3); 38 | validator.IsMinLength(input, 4); 39 | validator.IsMinLength(input, 5); 40 | validator.IsMinLength(input, 6); 41 | validator.IsMinLength(input, 7); 42 | 43 | Assert.IsTrue(validator.Errors.Count == 7); 44 | } 45 | 46 | [TestMethod] 47 | public void Test_IsMinLength_String_Empty() 48 | { 49 | string input = string.Empty; 50 | 51 | Validator validator = new Validator(); 52 | 53 | validator.IsMinLength(input, 1); 54 | validator.IsMinLength(input, 2); 55 | validator.IsMinLength(input, 3); 56 | validator.IsMinLength(input, 4); 57 | validator.IsMinLength(input, 5); 58 | validator.IsMinLength(input, 6); 59 | validator.IsMinLength(input, 7); 60 | 61 | Assert.IsTrue(validator.Errors.Count == 7); 62 | } 63 | 64 | [TestMethod] 65 | public void Test_IsMinLength_With_Name() 66 | { 67 | string input = "12345"; 68 | 69 | Validator validator = new Validator(); 70 | 71 | validator.IsMinLength("Input1", input, 1); 72 | validator.IsMinLength("Input2", input, 2); 73 | validator.IsMinLength("Input3", input, 3); 74 | validator.IsMinLength("Input4", input, 4); 75 | validator.IsMinLength("Input5", input, 5); 76 | validator.IsMinLength("Input6", input, 6); 77 | validator.IsMinLength("Input7", input, 7); 78 | 79 | Assert.IsTrue(validator.Errors.Count == 2, "Error Count"); 80 | Assert.IsTrue(validator.Errors[0].Name == "Input6", "Error 1 Name"); 81 | Assert.IsTrue(validator.Errors[1].Name == "Input7", "Error 2 Name"); 82 | } 83 | 84 | [TestMethod] 85 | public void Test_IsMinLength_With_Name_Message() 86 | { 87 | string input = "12345"; 88 | 89 | Validator validator = new Validator(); 90 | 91 | validator.IsMinLength("Input", input, 1, "Message1"); 92 | validator.IsMinLength("Input", input, 2, "Message2"); 93 | validator.IsMinLength("Input", input, 3, "Message3"); 94 | validator.IsMinLength("Input", input, 4, "Message4"); 95 | validator.IsMinLength("Input", input, 5, "Message5"); 96 | validator.IsMinLength("Input", input, 6, "Message6"); 97 | validator.IsMinLength("Input", input, 7, "Message7"); 98 | 99 | Assert.IsTrue(validator.Errors.Count == 2); 100 | Assert.IsTrue(validator.Errors[0].Message == "Message6"); 101 | Assert.IsTrue(validator.Errors[1].Message == "Message7"); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/SimpleValidator.Tests/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace SimpleValidator.Tests.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SimpleValidator.Tests.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to # Reserved Strings 65 | ///# 66 | ///# Strings which may be used elsewhere in code 67 | /// 68 | ///undefined 69 | ///undef 70 | ///null 71 | ///NULL 72 | ///(null) 73 | ///nil 74 | ///NIL 75 | ///true 76 | ///false 77 | ///True 78 | ///False 79 | ///None 80 | ///\ 81 | ///\\ 82 | /// 83 | ///# Numeric Strings 84 | ///# 85 | ///# Strings which can be interpreted as numeric 86 | /// 87 | ///0 88 | ///1 89 | ///1.00 90 | ///$1.00 91 | ///1/2 92 | ///1E2 93 | ///1E02 94 | ///1E+02 95 | ///-1 96 | ///-1.00 97 | ///-$1.00 98 | ///-1/2 99 | ///-1E2 100 | ///-1E02 101 | ///-1E+02 102 | ///1/0 103 | ///0/0 104 | ///-2147483648/-1 105 | ///-9223372036854775808/-1 106 | ///0.00 107 | ///0..0 108 | ///. 109 | ///0.0.0 110 | ///0,00 111 | ///0,,0 112 | ///, 113 | ///0,0,0 114 | ///0.0/0 115 | ///1.0/0.0 116 | ///0.0/0.0 117 | ///1,0/0,0 118 | ///0,0/0,0 119 | ///--1 120 | ///- 121 | ///-. 122 | ///-, 123 | ///999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 124 | /// [rest of string was truncated]";. 125 | /// 126 | internal static string Input { 127 | get { 128 | return ResourceManager.GetString("Input", resourceCulture); 129 | } 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/SimpleValidator.Tests/Validator_Date_Tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SimpleValidator; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using System.Collections.Generic; 5 | 6 | namespace SimpleValidator.Tests 7 | { 8 | [TestClass] 9 | public class Validator_Date_Tests 10 | { 11 | [TestMethod] 12 | public void Test_IsGreaterThan() 13 | { 14 | Validator validator = new Validator(); 15 | 16 | validator.IsGreaterThan(DateTime.Now, DateTime.Now.AddSeconds(-5)); 17 | validator.IsGreaterThan(DateTime.Now, DateTime.Now.AddMinutes(-5)); 18 | validator.IsGreaterThan(DateTime.Now.Date, DateTime.Now.AddDays(-1)); 19 | validator.IsGreaterThan(DateTime.Now, DateTime.Now.AddSeconds(1)); // fail 20 | 21 | Assert.IsTrue(validator.Errors.Count == 1); 22 | } 23 | 24 | [TestMethod] 25 | public void Test_IsGreaterThanOrEqualTo() 26 | { 27 | Validator validator = new Validator(); 28 | 29 | validator.IsGreaterThanOrEqualTo(DateTime.Now, DateTime.Now.AddSeconds(-5)); 30 | validator.IsGreaterThanOrEqualTo(DateTime.Now, DateTime.Now.AddMinutes(-5)); 31 | validator.IsGreaterThanOrEqualTo(DateTime.Now.Date, DateTime.Now.AddDays(-1)); 32 | validator.IsGreaterThanOrEqualTo(DateTime.Now, DateTime.Now); 33 | validator.IsGreaterThanOrEqualTo(DateTime.Now.Date, DateTime.Now.AddDays(-1).Date); 34 | validator.IsGreaterThanOrEqualTo(DateTime.Now.Date, DateTime.Now.Date); 35 | validator.IsGreaterThan(DateTime.Now, DateTime.Now.AddSeconds(1)); // fail 36 | 37 | Assert.IsTrue(validator.Errors.Count == 1); 38 | } 39 | 40 | [TestMethod] 41 | public void Test_IsLessThan() 42 | { 43 | Validator validator = new Validator(); 44 | 45 | validator.IsLessThan(DateTime.Now, DateTime.Now.AddSeconds(5)); 46 | validator.IsLessThan(DateTime.Now, DateTime.Now.AddMinutes(5)); 47 | validator.IsLessThan(DateTime.Now.Date, DateTime.Now.AddDays(1)); 48 | validator.IsLessThan(DateTime.Now, DateTime.Now.AddSeconds(-1)); // fail 49 | 50 | Assert.IsTrue(validator.Errors.Count == 1); 51 | } 52 | 53 | [TestMethod] 54 | public void Test_IsLessThanOrEqualTo() 55 | { 56 | Validator validator = new Validator(); 57 | 58 | validator.IsLessThanOrEqualTo(DateTime.Now, DateTime.Now.AddSeconds(5)); 59 | validator.IsLessThanOrEqualTo(DateTime.Now, DateTime.Now.AddMinutes(5)); 60 | validator.IsLessThanOrEqualTo(DateTime.Now.Date, DateTime.Now.AddDays(1)); 61 | validator.IsLessThanOrEqualTo(DateTime.Now, DateTime.Now); 62 | validator.IsLessThanOrEqualTo(DateTime.Now.Date, DateTime.Now.AddDays(1).Date); 63 | validator.IsLessThanOrEqualTo(DateTime.Now.Date, DateTime.Now.Date); 64 | validator.IsLessThanOrEqualTo(DateTime.Now, DateTime.Now.AddSeconds(-1)); // fail 65 | 66 | Assert.IsTrue(validator.Errors.Count == 1); 67 | } 68 | 69 | [TestMethod] 70 | public void Test_IsEqualTo() 71 | { 72 | Validator validator = new Validator(); 73 | 74 | validator.IsEqualTo(DateTime.Now, DateTime.Now.AddSeconds(5)); // fail 75 | validator.IsEqualTo(DateTime.Now, DateTime.Now); 76 | validator.IsEqualTo(DateTime.Now.Date, DateTime.Now.Date); 77 | validator.IsEqualTo(DateTime.Now, DateTime.Now.AddMilliseconds(-1)); // fail 78 | 79 | Assert.IsTrue(validator.Errors.Count == 2); 80 | } 81 | 82 | [TestMethod] 83 | public void Test_IsBetweenInclusive() 84 | { 85 | Validator validator = new Validator(); 86 | 87 | validator.IsBetweenInclusive(new DateTime(2016, 1, 10), new DateTime(2016, 1, 8), new DateTime(2016, 1, 12)); 88 | validator.IsBetweenInclusive(new DateTime(2016, 1, 8), new DateTime(2016, 1, 8), new DateTime(2016, 1, 12)); 89 | validator.IsBetweenInclusive(new DateTime(2016, 1, 6), new DateTime(2016, 1, 8), new DateTime(2016, 1, 12)); // fail 90 | validator.IsBetweenInclusive(new DateTime(2016, 1, 12), new DateTime(2016, 1, 8), new DateTime(2016, 1, 12)); 91 | validator.IsBetweenInclusive(new DateTime(2016, 1, 14), new DateTime(2016, 1, 8), new DateTime(2016, 1, 12)); // fail 92 | 93 | Assert.IsTrue(validator.Errors.Count == 2); 94 | } 95 | 96 | [TestMethod] 97 | public void Test_IsBetweenExclusive() 98 | { 99 | Validator validator = new Validator(); 100 | 101 | validator.IsBetweenExclusive(new DateTime(2016, 1, 10), new DateTime(2016, 1, 8), new DateTime(2016, 1, 12)); 102 | validator.IsBetweenExclusive(new DateTime(2016, 1, 8), new DateTime(2016, 1, 8), new DateTime(2016, 1, 12)); // fail 103 | validator.IsBetweenExclusive(new DateTime(2016, 1, 6), new DateTime(2016, 1, 8), new DateTime(2016, 1, 12)); // fail 104 | validator.IsBetweenExclusive(new DateTime(2016, 1, 12), new DateTime(2016, 1, 8), new DateTime(2016, 1, 12)); // fail 105 | validator.IsBetweenExclusive(new DateTime(2016, 1, 14), new DateTime(2016, 1, 8), new DateTime(2016, 1, 12)); // fail 106 | 107 | Assert.IsTrue(validator.Errors.Count == 4); 108 | } 109 | 110 | 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/SimpleValidator.Tests/SimpleValidator.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | {B7E2D22E-1395-4DBB-84C8-605B119B7588} 7 | Library 8 | Properties 9 | SimpleValidator.Tests 10 | SimpleValidator.Tests 11 | v4.0 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 10.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | 40 | 3.5 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | False 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | True 61 | True 62 | Resources.resx 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | {ece65351-bda1-476b-8434-561753f0a0c7} 78 | SimpleValidator 79 | 80 | 81 | 82 | 83 | ResXFileCodeGenerator 84 | Resources.Designer.cs 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | False 95 | 96 | 97 | False 98 | 99 | 100 | False 101 | 102 | 103 | False 104 | 105 | 106 | 107 | 108 | 109 | 110 | 117 | -------------------------------------------------------------------------------- /src/SimpleValidator.Tests/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\input.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 123 | 124 | -------------------------------------------------------------------------------- /src/SimpleValidator/Validator.cs: -------------------------------------------------------------------------------- 1 | using SimpleValidator.Extensions; 2 | using SimpleValidator.Results; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Linq.Expressions; 7 | using System.Text; 8 | using SimpleValidator.Messages; 9 | using SimpleValidator.Interfaces; 10 | 11 | namespace SimpleValidator 12 | { 13 | /// 14 | /// Always use the positive route i.e. a true result should indicate validity therefore generally prefix with "Is" 15 | /// e.g. This field is not zero 16 | /// 17 | public partial class Validator 18 | { 19 | #region " Constructor " 20 | 21 | /// 22 | /// Validate properties and types using this class 23 | /// 24 | public Validator() 25 | { 26 | Errors = new List(); 27 | MessageContainer = MessageFactory.Create(); 28 | } 29 | 30 | public Validator(LanguageCodes code) 31 | { 32 | Errors = new List(); 33 | MessageContainer = MessageFactory.Create(code); 34 | } 35 | 36 | public Validator(MessageContainer container) 37 | { 38 | Errors = new List(); 39 | MessageContainer = container; 40 | } 41 | 42 | #endregion 43 | 44 | #region " Properties " 45 | 46 | public MessageContainer MessageContainer { get; set; } 47 | 48 | private ValidationError _LastError = null; 49 | 50 | public bool IsValid 51 | { 52 | get 53 | { 54 | return Errors.Count == 0; 55 | } 56 | } 57 | 58 | #endregion 59 | 60 | #region " Validation Errors " 61 | 62 | /// 63 | /// The full list of errors currently available 64 | /// 65 | public List Errors { get; set; } 66 | 67 | /// 68 | /// Returns a list of errors with the specified name 69 | /// 70 | /// 71 | /// 72 | public List ErrorByName(string name) 73 | { 74 | return Errors.Where(o => o.Name == name).ToList(); 75 | } 76 | 77 | /// 78 | /// This will return a unique set of Errors by Name and return the first instance of each error. 79 | /// 80 | public List UniqueErrors 81 | { 82 | get 83 | { 84 | return Errors 85 | .GroupBy(o => o.Name) 86 | .Select(o => o.First()) 87 | .ToList(); 88 | } 89 | } 90 | 91 | #endregion 92 | 93 | #region " Validation Methods " 94 | 95 | #region " IsNotNull " 96 | 97 | public Validator IsNotNull(object value) 98 | { 99 | return IsNotNull("", value); 100 | } 101 | 102 | public Validator IsNotNull(string name, object value) 103 | { 104 | return IsNotNull(name, value, string.Format(MessageContainer.IsNotNullMessage, name)); 105 | } 106 | 107 | public Validator IsNotNull(string name, object value, string message) 108 | { 109 | // do the check 110 | if (value.IsNotNull()) 111 | { 112 | return NoError(); 113 | } 114 | else 115 | { 116 | return AddError(name, message); 117 | } 118 | } 119 | 120 | #endregion 121 | 122 | #region " Is " 123 | 124 | public Validator Is(Func func) 125 | { 126 | return Is("", func); 127 | } 128 | 129 | public Validator Is(string name, Func func) 130 | { 131 | return Is(name, func, MessageContainer.IsMessage); 132 | } 133 | 134 | public Validator Is(string name, Func func, string message) 135 | { 136 | // do the check 137 | if (func()) 138 | { 139 | return NoError(); 140 | } 141 | else 142 | { 143 | return AddError(name, message); 144 | } 145 | } 146 | 147 | #endregion 148 | 149 | #region " IsNot " 150 | 151 | public Validator IsNot(Func func) 152 | { 153 | return IsNot("", func); 154 | } 155 | 156 | public Validator IsNot(string name, Func func) 157 | { 158 | return IsNot(name, func, MessageContainer.IsNotMessage); 159 | } 160 | 161 | public Validator IsNot(string name, Func func, string message) 162 | { 163 | // do the check 164 | if (func()) 165 | { 166 | return AddError(name, message); 167 | } 168 | else 169 | { 170 | return NoError(); 171 | } 172 | } 173 | 174 | #endregion 175 | 176 | #region " IsRule " 177 | 178 | public Validator IsRule(IRule rule) 179 | { 180 | return IsRule("", rule); 181 | } 182 | 183 | public Validator IsRule(string name, IRule rule) 184 | { 185 | return IsRule(name, rule, MessageContainer.IsRuleMessage); 186 | } 187 | 188 | public Validator IsRule(string name, IRule rule, string message) 189 | { 190 | // do the check 191 | if (name.IsRule(rule)) 192 | { 193 | return NoError(); 194 | } 195 | else 196 | { 197 | return AddError(name, message); 198 | } 199 | } 200 | 201 | #endregion 202 | 203 | #endregion 204 | 205 | #region " WithMessage " 206 | 207 | public Validator WithMessage(string message) 208 | { 209 | if (_LastError != null) 210 | { 211 | _LastError.Message = message; 212 | } 213 | 214 | return this; 215 | } 216 | 217 | #endregion 218 | 219 | #region " Helpers " 220 | 221 | public Validator AddError(string message) 222 | { 223 | return AddError("", message); 224 | } 225 | 226 | public Validator AddError(string name, string message) 227 | { 228 | ValidationError error = ValidationError.Create(name.EmptyStringIfNull(), message); 229 | Errors.Add(error); 230 | _LastError = error; 231 | 232 | return this; 233 | } 234 | 235 | public void ThrowValidationException() 236 | { 237 | throw new Exceptions.ValidationException(this); 238 | } 239 | 240 | /// 241 | /// Throws an exception if errors are found 242 | /// 243 | /// If no errors are found it returns an instance of the validator. 244 | public Validator ThrowValidationExceptionIfInvalid() 245 | { 246 | if (!IsValid) 247 | { 248 | throw new Exceptions.ValidationException(this); 249 | } 250 | 251 | return this; 252 | } 253 | 254 | protected Validator NoError() 255 | { 256 | _LastError = null; 257 | return this; 258 | } 259 | 260 | #endregion 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /src/SimpleValidator.Tests/Extensions_Tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SimpleValidator; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using SimpleValidator.Extensions; 7 | 8 | namespace SimpleValidator.Tests 9 | { 10 | [TestClass] 11 | public class Extensions_Tests 12 | { 13 | #region " Helpers " 14 | 15 | public static List GetTestListObjectNullEmptyAndWhiteSpace() 16 | { 17 | List objects = new List(); 18 | 19 | objects.Add(null); 20 | objects.Add(string.Empty); 21 | objects.Add(""); 22 | objects.Add(" "); 23 | objects.Add(" "); 24 | objects.Add(@"\t"); 25 | objects.Add(@"\n\r"); 26 | objects.Add(@"\r"); 27 | objects.Add(Guid.NewGuid()); 28 | objects.Add(true); 29 | objects.Add("null"); 30 | 31 | return objects; 32 | } 33 | 34 | public static List GetTestListStringNullEmptyAndWhiteSpace() 35 | { 36 | List objects = new List(); 37 | 38 | objects.Add(null); 39 | objects.Add(string.Empty); 40 | objects.Add(""); 41 | objects.Add(" "); 42 | objects.Add(" "); 43 | objects.Add(@"\t"); 44 | objects.Add(@"\n\r"); 45 | objects.Add(@"\r"); 46 | objects.Add(Guid.NewGuid().ToString()); 47 | objects.Add("null"); 48 | 49 | return objects; 50 | } 51 | 52 | #endregion 53 | 54 | [TestMethod] 55 | public void Test_IsNotNullOrEmpty() 56 | { 57 | List inputs = new List() 58 | { 59 | null, // fail 60 | string.Empty, // fail 61 | "", // fail 62 | " ", 63 | " ", 64 | "\t", 65 | "\n\r", 66 | "\r", 67 | " ", 68 | "abcdef", 69 | "null", 70 | "⁰⁴⁵₀₁₂", 71 | "田中さんにあげて下さい", 72 | "😍", 73 | "﷽", 74 | " ", 75 | "␣" 76 | }; 77 | 78 | int fails = 0; 79 | 80 | foreach (var item in inputs) 81 | { 82 | if (!item.IsNotNullOrEmpty()) 83 | { 84 | fails++; 85 | } 86 | } 87 | 88 | Assert.IsTrue(fails == 3); 89 | } 90 | 91 | [TestMethod] 92 | public void Test_IsNotNullOrWhiteSpace() 93 | { 94 | List inputs = new List() 95 | { 96 | null, // fail 97 | string.Empty, // fail 98 | "", // fail 99 | " ", // fail 100 | " ", // fail 101 | "\t", // fail 102 | "\n\r", // fail 103 | "\r", // fail 104 | " ", 105 | "abcdef", 106 | "null", 107 | "⁰⁴⁵₀₁₂", 108 | "田中さんにあげて下さい", 109 | "😍", 110 | "﷽", 111 | " ", // fail 112 | "␣", 113 | Environment.NewLine // fail 114 | }; 115 | 116 | int fails = 0; 117 | 118 | foreach (var item in inputs) 119 | { 120 | if (!item.IsNotNullOrWhiteSpace()) 121 | { 122 | fails++; 123 | } 124 | } 125 | 126 | Assert.IsTrue(fails == 10); 127 | } 128 | 129 | [TestMethod] 130 | public void Test_IsBetweenLength() 131 | { 132 | List inputs = new List() 133 | { 134 | null, // fail 135 | string.Empty, // fail 136 | "", // fail 137 | " ", // fail 138 | " ", 139 | "1", // fail 140 | "12", // fail 141 | "123", 142 | "12345", 143 | "123456", // fail 144 | "1234567", // fail 145 | " " // fail 146 | }; 147 | 148 | int fails = 0; 149 | 150 | foreach (var item in inputs) 151 | { 152 | if (!item.IsBetweenLength(3, 5)) 153 | { 154 | fails++; 155 | } 156 | } 157 | 158 | Assert.IsTrue(fails == 9); 159 | } 160 | 161 | [TestMethod] 162 | public void Test_IsMaxLength() 163 | { 164 | List inputs = new List() 165 | { 166 | null, 167 | string.Empty, 168 | "", 169 | " ", 170 | " ", 171 | "1", 172 | "12", 173 | "123", 174 | "12345", 175 | "123456", // fail 176 | "1234567", // fail 177 | " " // fail 178 | }; 179 | 180 | int fails = 0; 181 | 182 | foreach (var item in inputs) 183 | { 184 | if (!item.IsMaxLength(5)) 185 | { 186 | fails++; 187 | } 188 | } 189 | 190 | Assert.IsTrue(fails == 3); 191 | } 192 | 193 | [TestMethod] 194 | public void Test_IsMinLength() 195 | { 196 | List inputs = new List() 197 | { 198 | null, // fail 199 | string.Empty, // fail 200 | "", // fail 201 | " ", // fail 202 | " ", 203 | "1", // fail 204 | "12", // fail 205 | "123", 206 | "12345", 207 | "123456", 208 | "1234567", 209 | " " 210 | }; 211 | 212 | int fails = 0; 213 | 214 | foreach (var item in inputs) 215 | { 216 | if (!item.IsMinLength(0)) 217 | { 218 | fails++; 219 | } 220 | } 221 | 222 | foreach (var item in inputs) 223 | { 224 | if (!item.IsMinLength(3)) 225 | { 226 | fails++; 227 | } 228 | } 229 | 230 | Assert.IsTrue(fails == 6); 231 | } 232 | 233 | [TestMethod] 234 | public void Test_IsExactLength() 235 | { 236 | List inputs = new List() 237 | { 238 | null, 239 | string.Empty, 240 | "", 241 | " ", 242 | " ", 243 | "1", 244 | "12", 245 | "123", 246 | "12345", 247 | "123456", 248 | "1234567", 249 | " " 250 | }; 251 | 252 | int fails = 0; 253 | 254 | foreach (var item in inputs) 255 | { 256 | if (!item.IsExactLength(0)) 257 | { 258 | fails++; 259 | } 260 | } // 9 fails 261 | 262 | foreach (var item in inputs) 263 | { 264 | if (!item.IsExactLength(3)) 265 | { 266 | fails++; 267 | } 268 | } // 10 fails 269 | 270 | Assert.IsTrue(fails == 19); 271 | } 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /src/SimpleValidator/Validator.Strings.cs: -------------------------------------------------------------------------------- 1 | using SimpleValidator.Extensions; 2 | using SimpleValidator.Results; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Globalization; 6 | using System.Linq; 7 | using System.Linq.Expressions; 8 | using System.Text; 9 | 10 | namespace SimpleValidator 11 | { 12 | public partial class Validator 13 | { 14 | #region " IsNotNullOrEmpty " 15 | 16 | public Validator IsNotNullOrEmpty(string value) 17 | { 18 | return IsNotNullOrEmpty("", value); 19 | } 20 | 21 | public Validator IsNotNullOrEmpty(string name, string value) 22 | { 23 | return IsNotNullOrEmpty(name, value, string.Format(MessageContainer.IsNotNullOrEmptyMessage, name)); 24 | } 25 | 26 | public Validator IsNotNullOrEmpty(string name, string value, string message) 27 | { 28 | // do the check 29 | if (value.IsNotNullOrEmpty()) 30 | { 31 | return NoError(); 32 | } 33 | else 34 | { 35 | return AddError(name, message); 36 | } 37 | } 38 | 39 | #endregion 40 | 41 | #region " IsNotNullOrWhiteSpace " 42 | 43 | public Validator IsNotNullOrWhiteSpace(string value) 44 | { 45 | return IsNotNullOrWhiteSpace("", value); 46 | } 47 | 48 | public Validator IsNotNullOrWhiteSpace(string name, string value) 49 | { 50 | return IsNotNullOrWhiteSpace(name, value, string.Format(MessageContainer.IsNotNullOrWhiteSpaceMessage, name)); 51 | } 52 | 53 | public Validator IsNotNullOrWhiteSpace(string name, string value, string message) 54 | { 55 | // do the check 56 | if (value.IsNotNullOrWhiteSpace()) 57 | { 58 | return NoError(); 59 | } 60 | else 61 | { 62 | return AddError(name, message); 63 | } 64 | } 65 | 66 | #endregion 67 | 68 | #region " IsEmail " 69 | 70 | public Validator IsEmail(string value) 71 | { 72 | return IsEmail("", value); 73 | } 74 | 75 | public Validator IsEmail(string name, string value) 76 | { 77 | return IsEmail(name, value, string.Format(MessageContainer.IsEmailMessage, name)); 78 | } 79 | 80 | public Validator IsEmail(string name, string value, string message) 81 | { 82 | // do the check 83 | if (value.IsEmail()) 84 | { 85 | return NoError(); 86 | } 87 | else 88 | { 89 | return AddError(name, message); 90 | } 91 | } 92 | 93 | #endregion 94 | 95 | #region " IsRegex " 96 | 97 | public Validator IsRegex(string value, string exp) 98 | { 99 | return IsRegex("", value, exp); 100 | } 101 | 102 | public Validator IsRegex(string name, string value, string exp) 103 | { 104 | return IsRegex(name, value, exp, string.Format(MessageContainer.IsRegexMessage, name)); 105 | } 106 | 107 | public Validator IsRegex(string name, string value, string exp, string message) 108 | { 109 | // do the check 110 | if (value.IsRegex(exp)) 111 | { 112 | return NoError(); 113 | } 114 | else 115 | { 116 | return AddError(name, message); 117 | } 118 | } 119 | 120 | #endregion 121 | 122 | #region " IsPassword " 123 | 124 | public Validator IsPassword(string value) 125 | { 126 | return IsPassword("", value); 127 | } 128 | 129 | public Validator IsPassword(string name, string value) 130 | { 131 | return IsPassword(name, value, string.Format(MessageContainer.IsPasswordMessage, name)); 132 | } 133 | 134 | public Validator IsPassword(string name, string value, string message) 135 | { 136 | // do the check 137 | if (!value.IsPassword()) 138 | { 139 | return AddError(name, message); 140 | } 141 | else 142 | { 143 | return NoError(); 144 | } 145 | } 146 | 147 | #endregion 148 | 149 | #region " IsEqualTo " 150 | 151 | public Validator IsMatch(string value, string compare) 152 | { 153 | return IsMatch("", value, compare); 154 | } 155 | 156 | public Validator IsMatch(string name, string value, string compare) 157 | { 158 | return IsMatch(name, value, compare, string.Format(MessageContainer.IsMatchMessage, name)); 159 | } 160 | 161 | public Validator IsMatch(string name, string value, string compare, string message) 162 | { 163 | // do the check 164 | if (!value.IsEqualTo(compare)) 165 | { 166 | return AddError(name, message); 167 | } 168 | else 169 | { 170 | return NoError(); 171 | } 172 | } 173 | 174 | #endregion 175 | 176 | #region " IsMinLength " 177 | 178 | public Validator IsMinLength(string value, int min) 179 | { 180 | return IsMinLength("", value, min); 181 | } 182 | 183 | public Validator IsMinLength(string name, string value, int min) 184 | { 185 | return IsMinLength(name, value, min, string.Format(MessageContainer.IsMinLengthMessage, name, min)); 186 | } 187 | 188 | public Validator IsMinLength(string name, string value, int min, string message) 189 | { 190 | // do the check 191 | if (value.IsMinLength(min)) 192 | { 193 | return NoError(); 194 | } 195 | else 196 | { 197 | return AddError(name, message); 198 | } 199 | } 200 | 201 | #endregion 202 | 203 | #region " IsMaxLength " 204 | 205 | public Validator IsMaxLength(string value, int max) 206 | { 207 | return IsMaxLength("", value, max); 208 | } 209 | 210 | public Validator IsMaxLength(string name, string value, int max) 211 | { 212 | return IsMaxLength(name, value, max, string.Format(MessageContainer.IsMaxLengthMessage, name, max)); 213 | } 214 | 215 | public Validator IsMaxLength(string name, string value, int max, string message) 216 | { 217 | // do the check 218 | if (value.IsMaxLength(max)) 219 | { 220 | return NoError(); 221 | 222 | } 223 | else 224 | { 225 | return AddError(name, message); 226 | } 227 | } 228 | 229 | #endregion 230 | 231 | #region " IsBetweenLength " 232 | 233 | public Validator IsBetweenLength(string value, int min, int max) 234 | { 235 | return IsBetweenLength("", value, min, max); 236 | } 237 | 238 | public Validator IsBetweenLength(string name, string value, int min, int max) 239 | { 240 | return IsBetweenLength(name, value, min, max, string.Format(MessageContainer.IsBetweenLengthMessage, name, min, max)); 241 | } 242 | 243 | public Validator IsBetweenLength(string name, string value, int min, int max, string message) 244 | { 245 | // do the check 246 | if (value.IsBetweenLength(min, max)) 247 | { 248 | return NoError(); 249 | } 250 | else 251 | { 252 | return AddError(name, message); 253 | } 254 | } 255 | 256 | #endregion 257 | 258 | #region " IsExactLength " 259 | 260 | public Validator IsExactLength(string value, int exact) 261 | { 262 | return IsExactLength("", value, exact); 263 | } 264 | 265 | public Validator IsExactLength(string name, string value, int exact) 266 | { 267 | return IsExactLength(name, value, exact, string.Format(MessageContainer.IsExactLengthMessage, name, exact)); 268 | } 269 | 270 | public Validator IsExactLength(string name, string value, int exact, string message) 271 | { 272 | // do the check 273 | if (!value.IsExactLength(exact)) 274 | { 275 | return AddError(name, message); 276 | } 277 | else 278 | { 279 | return NoError(); 280 | } 281 | } 282 | 283 | #endregion 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /src/SimpleValidator/Validator.Dates.cs: -------------------------------------------------------------------------------- 1 | using SimpleValidator.Extensions; 2 | using SimpleValidator.Results; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Globalization; 6 | using System.Linq; 7 | using System.Linq.Expressions; 8 | using System.Text; 9 | 10 | namespace SimpleValidator 11 | { 12 | public partial class Validator 13 | { 14 | #region " IsDate " 15 | 16 | public Validator IsDate(object value) 17 | { 18 | return IsDate("", value); 19 | } 20 | 21 | public Validator IsDate(string name, object value) 22 | { 23 | return IsDate(name, value, string.Format(MessageContainer.IsDateMessage, name)); 24 | } 25 | 26 | public Validator IsDate(string name, object value, string message) 27 | { 28 | // do the check 29 | if (value.IsDate()) 30 | { 31 | return NoError(); 32 | } 33 | else 34 | { 35 | return AddError(name, message); 36 | } 37 | } 38 | 39 | public Validator IsDate(object value, CultureInfo info) 40 | { 41 | return IsDate("", value, info); 42 | } 43 | 44 | public Validator IsDate(string name, object value, CultureInfo info) 45 | { 46 | return IsDate(name, value, string.Format(MessageContainer.IsDateMessage, name), info); 47 | } 48 | 49 | public Validator IsDate(string name, object value, string message, CultureInfo info) 50 | { 51 | // do the check 52 | if (value.IsDate(info)) 53 | { 54 | return NoError(); 55 | } 56 | else 57 | { 58 | return AddError(name, message); 59 | } 60 | } 61 | 62 | public Validator IsDate(object value, CultureInfo info, DateTimeStyles styles) 63 | { 64 | return IsDate(string.Empty, value, info, styles); 65 | } 66 | 67 | public Validator IsDate(string name, object value, CultureInfo info, DateTimeStyles styles) 68 | { 69 | return IsDate(name, value, string.Format(MessageContainer.IsDateMessage, name), info, styles); 70 | } 71 | 72 | public Validator IsDate(string name, object value, string message, CultureInfo info, DateTimeStyles styles) 73 | { 74 | // do the check 75 | if (value.IsDate(info, styles)) 76 | { 77 | return NoError(); 78 | } 79 | else 80 | { 81 | return AddError(name, message); 82 | } 83 | } 84 | 85 | #endregion 86 | 87 | #region " IsGreaterThan " 88 | 89 | public Validator IsGreaterThan(DateTime value, DateTime compare) 90 | { 91 | return IsGreaterThan("", value, compare); 92 | } 93 | 94 | public Validator IsGreaterThan(string name, DateTime value, DateTime compare) 95 | { 96 | return IsGreaterThan(name, value, compare, string.Format(MessageContainer.IsGreaterThanMessage, name, compare)); 97 | } 98 | 99 | public Validator IsGreaterThan(string name, DateTime value, DateTime compare, string message) 100 | { 101 | // do the check 102 | if (value.IsGreaterThan(compare)) 103 | { 104 | return NoError(); 105 | } 106 | else 107 | { 108 | return AddError(name, message); 109 | } 110 | } 111 | 112 | #endregion 113 | 114 | #region " IsGreaterThanOrEqualTo " 115 | 116 | public Validator IsGreaterThanOrEqualTo(DateTime value, DateTime compare) 117 | { 118 | return IsGreaterThanOrEqualTo("", value, compare); 119 | } 120 | 121 | public Validator IsGreaterThanOrEqualTo(string name, DateTime value, DateTime compare) 122 | { 123 | return IsGreaterThanOrEqualTo(name, value, compare, string.Format(MessageContainer.IsGreaterThanOrEqualToMessage, name, compare)); 124 | } 125 | 126 | public Validator IsGreaterThanOrEqualTo(string name, DateTime value, DateTime compare, string message) 127 | { 128 | // do the check 129 | if (value.IsGreaterThanOrEqualTo(compare)) 130 | { 131 | return NoError(); 132 | } 133 | else 134 | { 135 | return AddError(name, message); 136 | } 137 | } 138 | 139 | #endregion 140 | 141 | #region " IsLessThan " 142 | 143 | public Validator IsLessThan(DateTime value, DateTime compare) 144 | { 145 | return IsLessThan("", value, compare); 146 | } 147 | 148 | public Validator IsLessThan(string name, DateTime value, DateTime compare) 149 | { 150 | return IsLessThan(name, value, compare, string.Format(MessageContainer.IsLessThanMessage, name, compare)); 151 | } 152 | 153 | public Validator IsLessThan(string name, DateTime value, DateTime compare, string message) 154 | { 155 | // do the check 156 | if (value.IsLessThan(compare)) 157 | { 158 | return NoError(); 159 | } 160 | else 161 | { 162 | return AddError(name, message); 163 | } 164 | } 165 | 166 | #endregion 167 | 168 | #region " IsLessThanOrEqualTo " 169 | 170 | public Validator IsLessThanOrEqualTo(DateTime value, DateTime compare) 171 | { 172 | return IsLessThanOrEqualTo("", value, compare); 173 | } 174 | 175 | public Validator IsLessThanOrEqualTo(string name, DateTime value, DateTime compare) 176 | { 177 | return IsLessThanOrEqualTo(name, value, compare, string.Format(MessageContainer.IsLessThanOrEqualToMessage, name, compare)); 178 | } 179 | 180 | public Validator IsLessThanOrEqualTo(string name, DateTime value, DateTime compare, string message) 181 | { 182 | // do the check 183 | if (value.IsLessThanOrEqualTo(compare)) 184 | { 185 | return NoError(); 186 | } 187 | else 188 | { 189 | return AddError(name, message); 190 | } 191 | } 192 | 193 | #endregion 194 | 195 | #region " IsEqualTo " 196 | 197 | public Validator IsEqualTo(DateTime value, DateTime compare) 198 | { 199 | return IsEqualTo("", value, compare); 200 | } 201 | 202 | public Validator IsEqualTo(string name, DateTime value, DateTime compare) 203 | { 204 | return IsEqualTo(name, value, compare, string.Format(MessageContainer.IsEqualToMessage, name, compare)); 205 | } 206 | 207 | public Validator IsEqualTo(string name, DateTime value, DateTime compare, string message) 208 | { 209 | // do the check 210 | if (value.IsEqualTo(compare)) 211 | { 212 | return NoError(); 213 | } 214 | else 215 | { 216 | return AddError(name, message); 217 | } 218 | } 219 | 220 | #endregion 221 | 222 | #region " IsBetweenInclusive " 223 | 224 | public Validator IsBetweenInclusive(DateTime value, DateTime from, DateTime to) 225 | { 226 | return IsBetweenInclusive("", value, from, to); 227 | } 228 | 229 | public Validator IsBetweenInclusive(string name, DateTime value, DateTime from, DateTime to) 230 | { 231 | return IsBetweenInclusive(name, value, from, to, string.Format(MessageContainer.IsBetweenInclusiveMessage, name, from, to)); 232 | } 233 | 234 | public Validator IsBetweenInclusive(string name, DateTime value, DateTime from, DateTime to, string message) 235 | { 236 | // do the check 237 | if (value.IsBetweenInclusive(from, to)) 238 | { 239 | return NoError(); 240 | } 241 | else 242 | { 243 | return AddError(name, message); 244 | } 245 | } 246 | 247 | #endregion 248 | 249 | #region " IsBetweenInclusive " 250 | 251 | public Validator IsBetweenExclusive(DateTime value, DateTime from, DateTime to) 252 | { 253 | return IsBetweenExclusive("", value, from, to); 254 | } 255 | 256 | public Validator IsBetweenExclusive(string name, DateTime value, DateTime from, DateTime to) 257 | { 258 | return IsBetweenExclusive(name, value, from, to, string.Format(MessageContainer.IsBetweenExclusiveMessage, name, from, to)); 259 | } 260 | 261 | public Validator IsBetweenExclusive(string name, DateTime value, DateTime from, DateTime to, string message) 262 | { 263 | // do the check 264 | if (value.IsBetweenExclusive(from, to)) 265 | { 266 | return NoError(); 267 | } 268 | else 269 | { 270 | return AddError(name, message); 271 | } 272 | } 273 | 274 | #endregion 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SimpleValidator 2 | 3 | A simple .Net validation library written in C# 4 | 5 | It's based largely on the [FluentValidation](https://github.com/JeremySkinner/FluentValidation) libary with some changes in it's usage. 6 | 7 | ## Why SimpleValidator? 8 | 9 | I needed a validation library that satisfied the following criteria: 10 | 11 | - Quick and simple validation checks 12 | - Complex business rule validation 13 | - Multiple stages of validation (i.e. do the simple stuff first, then more complex validation, but don't bother with the complex stuff if the simple stuff fails) 14 | - Avoid attribute based validation (I try to avoid using attributes. People think, I've validated my MVC model so my service method should be good to go. Not the case. Service methods should always validate everything as you cannot guarantee validation has been performed) 15 | - Readable 16 | - Central 17 | 18 | What I came up with was the following... 19 | 20 | As there is quite a bit to cover I'm going to start simply, and add complexity. 21 | 22 | ## Structure 23 | 24 | There is 2 types of validation you can perform using SimpleValidator. **Extension methods** and **Validator**. The validator 25 | essentially uses the extension methods behind the scenes but provides a useful wrapper for doing your validations and groups the error messages in a 26 | meaningful way. 27 | 28 | ## Extension methods 29 | 30 | As a start, there are some simple extension method you can use. 31 | 32 | Include the following using statement: 33 | 34 | ```using SimpleValidator.Extensions;``` 35 | 36 | Then you should have some useful helper methods as shown below: 37 | 38 | ``` 39 | string email = "test@email.com"; 40 | 41 | if (email.IsLength(5)) ... 42 | if (email.IsEmail()) ... 43 | if (email.IsMatch("test2@email.com")) ... 44 | if (email.IsInt()) ... 45 | if (email.IsNumber()) ... 46 | ``` 47 | 48 | The full list of extension methods is as follows: 49 | 50 | ``` 51 | // string based extension methods (IsNotNullOrEmpty and IsNotNullOrWhiteSpace are the only methods that have inverse tests. The assumption is to always assume the positive. 52 | [string].IsNotNullOrEmpty 53 | [string].IsNullOrEmpty 54 | [string].IsNotNullOrWhiteSpace 55 | [string].IsNullOrWhiteSpace(); 56 | [string].IsBetweenLength 57 | [string].IsMaxLength 58 | [string].IsMinLength 59 | [string].IsExactLength 60 | [string].IsEmail 61 | [string].IsPassword 62 | [string].IsCreditCard 63 | [string].IsEqualTo 64 | 65 | // object based extension methods 66 | [object].IsNotNull 67 | [object].IsNull 68 | [object].Is 69 | [object].IsNot 70 | [object].IsRule // validating against an interface for more complex business rules 71 | [object].IsInt 72 | [object].IsShort 73 | [object].IsLong 74 | [object].IsDouble 75 | [object].IsBool 76 | [object].IsNumber 77 | [object].Is 78 | 79 | // integer (same dor double, decimal, short and long) 80 | [integer].IsNotZero 81 | [integer].IsEqualTo 82 | [integer].IsGreaterThan 83 | [integer].IsLessThan 84 | [integer].IsBetween 85 | 86 | // datetime 87 | [datetime].IsDate 88 | [datetime].IsGreaterThan 89 | [datetime].IsGreaterThanOrEqualTo 90 | [datetime].IsLessThan 91 | [datetime].IsLessThanOrEqualTo 92 | [datetime].IsEqualTo 93 | [datetime].IsBetween 94 | [datetime].IsGreaterThanDateOnly 95 | [datetime].IsGreaterThanOrEqualToDateOnly 96 | [datetime].IsLessThanDateOnly 97 | [datetime].IsLessThanOrEqualToDateOnly 98 | [datetime].IsEqualToDateOnly 99 | [datetime].IsBetweenDateOnly 100 | ``` 101 | 102 | From here you also have access to some helpful conversion methods, e.g. 103 | 104 | ``` 105 | string input = "5"; 106 | 107 | if (input.IsInt()) 108 | return input.ToInt(); 109 | ``` 110 | 111 | A full list of these are as follows 112 | 113 | ``` 114 | .ToInt() 115 | .ToShort() 116 | .ToLong() 117 | .ToDouble() 118 | .ToDecimal() 119 | .ToBool() 120 | 121 | // and then a more generic one 122 | .To() 123 | 124 | ``` 125 | 126 | ## Validator 127 | 128 | Extension methods work great for quick simple checks, but you probably want to do more complex validation. 129 | 130 | For this, lets create a Validator object. From there you can use it to validate several properties of an object with a few overrides as shown below 131 | 132 | Remember to include ```using SimpleValidator;``` 133 | 134 | For each text method you have the following overrides: 135 | 136 | ``` 137 | SimpleValidator.Validator validator = new Validator(); 138 | 139 | // value 140 | validator.IsEmail("test@email.com"); 141 | 142 | // name, value 143 | validator.IsEmail("Email", "test@email.com"); 144 | 145 | // name, value, message 146 | validator.IsEmail("Email", "test@email.com", "Please enter a valid email address"); 147 | 148 | if (validator.IsValid()) 149 | { 150 | // everything is good 151 | } 152 | else 153 | { 154 | // validator.Errors contains a name / message dictionary of your errors 155 | } 156 | 157 | ``` 158 | 159 | 160 | 161 | It supports chaining so you could write it as follows 162 | 163 | ``` 164 | validator 165 | .IsEmail("test@email.com") 166 | .IsEmail("Email", "test@email.com", "This is an error message") 167 | .IsEmail("Email", "test@email.com").WithMessage("This is an error message") 168 | ``` 169 | 170 | This is quite usefull for more complex object validation e.g. 171 | ``` 172 | // validate the name 173 | validator 174 | .NotNull(name).WithMessage("Name cannot be an empty string") 175 | .IsLength(name, 5).WithMessage("Name must be at least 5 characters long") 176 | .IsLength(name, 5, 20).WithMessage("Name must between 5 and 20 characters") 177 | .Must(() => 178 | { 179 | return name.Contains("abc"); 180 | }).WithMessage("Name cannot contain abc") 181 | .MustNot(() => 182 | { 183 | return name.Contains("bob"); 184 | }).WithMessage("Name cannot contain bob"); 185 | ``` 186 | 187 | Each of the messages are added to an Error collection within the validator object. It also has a ```IsValid``` property. The validation is done as the method is called, which means you can stagger the validation if needed e.g. 188 | 189 | ``` 190 | string name = "Gordon"; 191 | 192 | // validate the name 193 | validator 194 | .NotNull(name).WithMessage("Name cannot be an empty string"); 195 | 196 | if (validator.IsValid) 197 | { 198 | // do something here that is dependant on name not being null 199 | 200 | validator.Must(() => 201 | { 202 | // some other condition 203 | return true; 204 | }); 205 | 206 | if (validator.IsValid) 207 | { 208 | // and down the rabit hole we go... 209 | } 210 | } 211 | ``` 212 | 213 | ### IRule 214 | 215 | For more complex validation you can use the ```Is``` and ```IsNot``` validation methods passing in a function which should return a bool. For more serious business rule validations, 216 | you can pass in any object implementing the ```IRule``` interface to the ```IsRule(...)``` method. All this combined gives you some flexibility on how you go about implementing your validation. 217 | 218 | Point is, every service method should implement validation for every incoming model. 219 | 220 | Ok, I have validation errors, now what? 221 | 222 | ## Implementation 223 | 224 | Let's say we have a method 225 | 226 | ``` 227 | private User AddUser(UserModel user) 228 | { 229 | } 230 | ``` 231 | 232 | You pass in a ```UserModel```, and if all goes well, the user is added and it returns a ```User``` object. 233 | 234 | What happens if we encounter validation errors? Once approach is to throw an exception (Not ideal but works) and the library has an exception ready for this. 235 | 236 | ### ValidationException 237 | 238 | ``` 239 | 240 | try 241 | { 242 | // ... 243 | ServiceManager.AddUser(model); 244 | // ... 245 | } 246 | catch (ValidationException ex) 247 | { 248 | // validation error - The validator is passed in as part of the exception so you can access the errors ex.Validator.Errors 249 | } 250 | catch (Exception ex) 251 | { 252 | // something else... woops 253 | } 254 | 255 | ``` 256 | 257 | And in your validation method. 258 | 259 | ``` 260 | private User AddUser(UserModel user) 261 | { 262 | Validator validator = new Validator(); 263 | // validation happens here... 264 | 265 | if (!validator.IsValid) 266 | { 267 | validator.ThrowValidationException(); 268 | } 269 | 270 | // or you can do this without the IsValid check (it checks it internally) 271 | validator.ThrowValidationExceptionIfInvalid(); 272 | } 273 | ``` 274 | ### ValidationMethodResult 275 | 276 | Another approach is to use the ```ValidationMethodResult```. Changing the above code it now looks as follows 277 | 278 | ``` 279 | public ValidationMethodResult AddUser(UserModel model) 280 | { 281 | Validator validator = new Validator(); 282 | 283 | // do validation 284 | 285 | return new ValidationMethodResult(validator, user); 286 | } 287 | 288 | ``` 289 | 290 | And then in your calling method 291 | 292 | ``` 293 | try 294 | { 295 | // ... 296 | var result = ServiceManager.AddUser(model); 297 | 298 | if (result.IsValid()) 299 | { 300 | // all good and you have access to the return user 301 | return Content(result.Result.Name); // The return users name... 302 | } 303 | else 304 | { 305 | // show errors using result.Errors 306 | } 307 | 308 | // ... 309 | } 310 | catch (Exception ex) 311 | { 312 | // something else... woops 313 | } 314 | 315 | ``` 316 | 317 | It's a cleaner approach, allows you to specify complex return types and provides a boolean indication reflecting the validation state of the current object. You could use simple out param's and use a boolean return 318 | type for all methods, but I'm not a fan (That doesn't mean it's not right) 319 | 320 | 321 | 322 | -------------------------------------------------------------------------------- /src/SimpleValidator.Tests/Resources/input.txt: -------------------------------------------------------------------------------- 1 | # Reserved Strings 2 | # 3 | # Strings which may be used elsewhere in code 4 | undefined 5 | undef 6 | null 7 | NULL 8 | (null) 9 | nil 10 | NIL 11 | true 12 | false 13 | True 14 | False 15 | None 16 | \ 17 | \\ 18 | 19 | 20 | 21 | 22 | # Numeric Strings 23 | # 24 | # Strings which can be interpreted as numeric 25 | 26 | 0 27 | 1 28 | 1.00 29 | $1.00 30 | 1/2 31 | 1E2 32 | 1E02 33 | 1E+02 34 | -1 35 | -1.00 36 | -$1.00 37 | -1/2 38 | -1E2 39 | -1E02 40 | -1E+02 41 | 1/0 42 | 0/0 43 | -2147483648/-1 44 | -9223372036854775808/-1 45 | 0.00 46 | 0..0 47 | . 48 | 0.0.0 49 | 0,00 50 | 0,,0 51 | , 52 | 0,0,0 53 | 0.0/0 54 | 1.0/0.0 55 | 0.0/0.0 56 | 1,0/0,0 57 | 0,0/0,0 58 | --1 59 | - 60 | -. 61 | -, 62 | 999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 63 | NaN 64 | Infinity 65 | -Infinity 66 | 0x0 67 | 0xffffffff 68 | 0xffffffffffffffff 69 | 0xabad1dea 70 | 123456789012345678901234567890123456789 71 | 1,000.00 72 | 1 000.00 73 | 1'000.00 74 | 1,000,000.00 75 | 1 000 000.00 76 | 1'000'000.00 77 | 1.000,00 78 | 1 000,00 79 | 1'000,00 80 | 1.000.000,00 81 | 1 000 000,00 82 | 1'000'000,00 83 | 01000 84 | 08 85 | 09 86 | 2.2250738585072011e-308 87 | 88 | # Special Characters 89 | # 90 | # Strings which contain common special ASCII characters (may need to be escaped) 91 | 92 | ,./;'[]\-= 93 | <>?:"{}|_+ 94 | !@#$%^&*()`~ 95 | 96 | # Unicode Symbols 97 | # 98 | # Strings which contain common unicode symbols (e.g. smart quotes) 99 | 100 | Ω≈ç√∫˜µ≤≥÷ 101 | åß∂ƒ©˙∆˚¬…æ 102 | œ∑´®†¥¨ˆøπ“‘ 103 | ¡™£¢∞§¶•ªº–≠ 104 | ¸˛Ç◊ı˜Â¯˘¿ 105 | ÅÍÎÏ˝ÓÔÒÚÆ☃ 106 | Œ„´‰ˇÁ¨ˆØ∏”’ 107 | `⁄€‹›fifl‡°·‚—± 108 | ⅛⅜⅝⅞ 109 | ЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя 110 | ٠١٢٣٤٥٦٧٨٩ 111 | 112 | # Unicode Subscript/Superscript 113 | # 114 | # Strings which contain unicode subscripts/superscripts; can cause rendering issues 115 | 116 | ⁰⁴⁵ 117 | ₀₁₂ 118 | ⁰⁴⁵₀₁₂ 119 | 120 | # Quotation Marks 121 | # 122 | # Strings which contain misplaced quotation marks; can cause encoding errors 123 | 124 | ' 125 | " 126 | '' 127 | "" 128 | '"' 129 | "''''"'" 130 | "'"'"''''" 131 | 132 | # Two-Byte Characters 133 | # 134 | # Strings which contain two-byte characters: can cause rendering issues or character-length issues 135 | 136 | 田中さんにあげて下さい 137 | パーティーへ行かないか 138 | 和製漢語 139 | 部落格 140 | 사회과학원 어학연구소 141 | 찦차를 타고 온 펲시맨과 쑛다리 똠방각하 142 | 社會科學院語學研究所 143 | 울란바토르 144 | 𠜎𠜱𠝹𠱓𠱸𠲖𠳏 145 | 146 | # Japanese Emoticons 147 | # 148 | # Strings which consists of Japanese-style emoticons which are popular on the web 149 | 150 | ヽ༼ຈل͜ຈ༽ノ ヽ༼ຈل͜ຈ༽ノ 151 | (。◕ ∀ ◕。) 152 | `ィ(´∀`∩ 153 | __ロ(,_,*) 154 | ・( ̄∀ ̄)・:*: 155 | ゚・✿ヾ╲(。◕‿◕。)╱✿・゚ 156 | ,。・:*:・゜’( ☻ ω ☻ )。・:*:・゜’ 157 | (╯°□°)╯︵ ┻━┻) 158 | (ノಥ益ಥ)ノ ┻━┻ 159 | ( ͡° ͜ʖ ͡°) 160 | 161 | # Emoji 162 | # 163 | # Strings which contain Emoji; should be the same behavior as two-byte characters, but not always 164 | 165 | 😍 166 | 👩🏽 167 | 👾 🙇 💁 🙅 🙆 🙋 🙎 🙍 168 | 🐵 🙈 🙉 🙊 169 | ❤️ 💔 💌 💕 💞 💓 💗 💖 💘 💝 💟 💜 💛 💚 💙 170 | ✋🏿 💪🏿 👐🏿 🙌🏿 👏🏿 🙏🏿 171 | 🚾 🆒 🆓 🆕 🆖 🆗 🆙 🏧 172 | 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 173 | 174 | # Unicode Numbers 175 | # 176 | # Strings which contain unicode numbers; if the code is localized, it should see the input as numeric 177 | 178 | 123 179 | ١٢٣ 180 | 181 | # Right-To-Left Strings 182 | # 183 | # Strings which contain text that should be rendered RTL if possible (e.g. Arabic, Hebrew) 184 | 185 | ثم نفس سقطت وبالتحديد،, جزيرتي باستخدام أن دنو. إذ هنا؟ الستار وتنصيب كان. أهّل ايطاليا، بريطانيا-فرنسا قد أخذ. سليمان، إتفاقية بين ما, يذكر الحدود أي بعد, معاملة بولندا، الإطلاق عل إيو. 186 | בְּרֵאשִׁית, בָּרָא אֱלֹהִים, אֵת הַשָּׁמַיִם, וְאֵת הָאָרֶץ 187 | הָיְתָהtestالصفحات التّحول 188 | ﷽ 189 | ﷺ 190 | 191 | # Unicode Spaces 192 | # 193 | # Strings which contain unicode space characters with special properties (c.f. https://www.cs.tut.fi/~jkorpela/chars/spaces.html) 194 | 195 | ​ 196 |   197 | ᠎ 198 |   199 |  200 | ␣ 201 | ␢ 202 | ␡ 203 | 204 | # Trick Unicode 205 | # 206 | # Strings which contain unicode with unusual properties (e.g. Right-to-left override) (c.f. http://www.unicode.org/charts/PDF/U2000.pdf) 207 | 208 | ‪‪test‪ 209 | ‫test‫ 210 | 211 | test 212 | 213 | test⁠test‫ 214 | ⁦test⁧ 215 | 216 | # Zalgo Text 217 | # 218 | # Strings which contain "corrupted" text. The corruption will not appear in non-HTML text, however. (via http://www.eeemo.net) 219 | 220 | Ṱ̺̺̕o͞ ̷i̲̬͇̪͙n̝̗͕v̟̜̘̦͟o̶̙̰̠kè͚̮̺̪̹̱̤ ̖t̝͕̳̣̻̪͞h̼͓̲̦̳̘̲e͇̣̰̦̬͎ ̢̼̻̱̘h͚͎͙̜̣̲ͅi̦̲̣̰̤v̻͍e̺̭̳̪̰-m̢iͅn̖̺̞̲̯̰d̵̼̟͙̩̼̘̳ ̞̥̱̳̭r̛̗̘e͙p͠r̼̞̻̭̗e̺̠̣͟s̘͇̳͍̝͉e͉̥̯̞̲͚̬͜ǹ̬͎͎̟̖͇̤t͍̬̤͓̼̭͘ͅi̪̱n͠g̴͉ ͏͉ͅc̬̟h͡a̫̻̯͘o̫̟̖͍̙̝͉s̗̦̲.̨̹͈̣ 221 | ̡͓̞ͅI̗̘̦͝n͇͇͙v̮̫ok̲̫̙͈i̖͙̭̹̠̞n̡̻̮̣̺g̲͈͙̭͙̬͎ ̰t͔̦h̞̲e̢̤ ͍̬̲͖f̴̘͕̣è͖ẹ̥̩l͖͔͚i͓͚̦͠n͖͍̗͓̳̮g͍ ̨o͚̪͡f̘̣̬ ̖̘͖̟͙̮c҉͔̫͖͓͇͖ͅh̵̤̣͚͔á̗̼͕ͅo̼̣̥s̱͈̺̖̦̻͢.̛̖̞̠̫̰ 222 | ̗̺͖̹̯͓Ṯ̤͍̥͇͈h̲́e͏͓̼̗̙̼̣͔ ͇̜̱̠͓͍ͅN͕͠e̗̱z̘̝̜̺͙p̤̺̹͍̯͚e̠̻̠͜r̨̤͍̺̖͔̖̖d̠̟̭̬̝͟i̦͖̩͓͔̤a̠̗̬͉̙n͚͜ ̻̞̰͚ͅh̵͉i̳̞v̢͇ḙ͎͟-҉̭̩̼͔m̤̭̫i͕͇̝̦n̗͙ḍ̟ ̯̲͕͞ǫ̟̯̰̲͙̻̝f ̪̰̰̗̖̭̘͘c̦͍̲̞͍̩̙ḥ͚a̮͎̟̙͜ơ̩̹͎s̤.̝̝ ҉Z̡̖̜͖̰̣͉̜a͖̰͙̬͡l̲̫̳͍̩g̡̟̼̱͚̞̬ͅo̗͜.̟ 223 | ̦H̬̤̗̤͝e͜ ̜̥̝̻͍̟́w̕h̖̯͓o̝͙̖͎̱̮ ҉̺̙̞̟͈W̷̼̭a̺̪͍į͈͕̭͙̯̜t̶̼̮s̘͙͖̕ ̠̫̠B̻͍͙͉̳ͅe̵h̵̬͇̫͙i̹͓̳̳̮͎̫̕n͟d̴̪̜̖ ̰͉̩͇͙̲͞ͅT͖̼͓̪͢h͏͓̮̻e̬̝̟ͅ ̤̹̝W͙̞̝͔͇͝ͅa͏͓͔̹̼̣l̴͔̰̤̟͔ḽ̫.͕ 224 | Z̮̞̠͙͔ͅḀ̗̞͈̻̗Ḷ͙͎̯̹̞͓G̻O̭̗̮ 225 | 226 | # Unicode Upsidedown 227 | # 228 | # Strings which contain unicode with an "upsidedown" effect (via http://www.upsidedowntext.com) 229 | 230 | ˙ɐnbᴉlɐ ɐuƃɐɯ ǝɹolop ʇǝ ǝɹoqɐl ʇn ʇunpᴉpᴉɔuᴉ ɹodɯǝʇ poɯsnᴉǝ op pǝs 'ʇᴉlǝ ƃuᴉɔsᴉdᴉpɐ ɹnʇǝʇɔǝsuoɔ 'ʇǝɯɐ ʇᴉs ɹolop ɯnsdᴉ ɯǝɹo˥ 231 | 00˙Ɩ$- 232 | 233 | # Unicode font 234 | # 235 | # Strings which contain bold/italic/etc. versions of normal characters 236 | 237 | The quick brown fox jumps over the lazy dog 238 | 𝐓𝐡𝐞 𝐪𝐮𝐢𝐜𝐤 𝐛𝐫𝐨𝐰𝐧 𝐟𝐨𝐱 𝐣𝐮𝐦𝐩𝐬 𝐨𝐯𝐞𝐫 𝐭𝐡𝐞 𝐥𝐚𝐳𝐲 𝐝𝐨𝐠 239 | 𝕿𝖍𝖊 𝖖𝖚𝖎𝖈𝖐 𝖇𝖗𝖔𝖜𝖓 𝖋𝖔𝖝 𝖏𝖚𝖒𝖕𝖘 𝖔𝖛𝖊𝖗 𝖙𝖍𝖊 𝖑𝖆𝖟𝖞 𝖉𝖔𝖌 240 | 𝑻𝒉𝒆 𝒒𝒖𝒊𝒄𝒌 𝒃𝒓𝒐𝒘𝒏 𝒇𝒐𝒙 𝒋𝒖𝒎𝒑𝒔 𝒐𝒗𝒆𝒓 𝒕𝒉𝒆 𝒍𝒂𝒛𝒚 𝒅𝒐𝒈 241 | 𝓣𝓱𝓮 𝓺𝓾𝓲𝓬𝓴 𝓫𝓻𝓸𝔀𝓷 𝓯𝓸𝔁 𝓳𝓾𝓶𝓹𝓼 𝓸𝓿𝓮𝓻 𝓽𝓱𝓮 𝓵𝓪𝔃𝔂 𝓭𝓸𝓰 242 | 𝕋𝕙𝕖 𝕢𝕦𝕚𝕔𝕜 𝕓𝕣𝕠𝕨𝕟 𝕗𝕠𝕩 𝕛𝕦𝕞𝕡𝕤 𝕠𝕧𝕖𝕣 𝕥𝕙𝕖 𝕝𝕒𝕫𝕪 𝕕𝕠𝕘 243 | 𝚃𝚑𝚎 𝚚𝚞𝚒𝚌𝚔 𝚋𝚛𝚘𝚠𝚗 𝚏𝚘𝚡 𝚓𝚞𝚖𝚙𝚜 𝚘𝚟𝚎𝚛 𝚝𝚑𝚎 𝚕𝚊𝚣𝚢 𝚍𝚘𝚐 244 | ⒯⒣⒠ ⒬⒰⒤⒞⒦ ⒝⒭⒪⒲⒩ ⒡⒪⒳ ⒥⒰⒨⒫⒮ ⒪⒱⒠⒭ ⒯⒣⒠ ⒧⒜⒵⒴ ⒟⒪⒢ 245 | 246 | # Script Injection 247 | # 248 | # Strings which attempt to invoke a benign script injection; shows vulnerability to XSS 249 | 250 | 251 | <script>alert('123');</script> 252 | 253 | 254 | "> 255 | '> 256 | > 257 | 258 | < / script >< script >alert(123)< / script > 259 | onfocus=JaVaSCript:alert(123) autofocus 260 | " onfocus=JaVaSCript:alert(123) autofocus 261 | ' onfocus=JaVaSCript:alert(123) autofocus 262 | <script>alert(123)</script> 263 | ript>alert(123)ript> 264 | --> 265 | ";alert(123);t=" 266 | ';alert(123);t=' 267 | JavaSCript:alert(123) 268 | ;alert(123); 269 | src=JaVaSCript:prompt(132) 270 | ">javascript:alert(1); 276 | javascript:alert(1); 277 | javascript:alert(1); 278 | javascript:alert(1); 279 | javascript:alert(1); 280 | javascript:alert(1); 281 | javascript:alert(1); 282 | '`"><\x3Cscript>javascript:alert(1) 283 | '`"><\x00script>javascript:alert(1) 284 | ABC
DEF 285 | ABC
DEF 286 | ABC
DEF 287 | ABC
DEF 288 | ABC
DEF 289 | ABC
DEF 290 | ABC
DEF 291 | ABC
DEF 292 | ABC
DEF 293 | ABC
DEF 294 | ABC
DEF 295 | ABC
DEF 296 | ABC
DEF 297 | ABC
DEF 298 | ABC
DEF 299 | ABC
DEF 300 | ABC
DEF 301 | ABC
DEF 302 | ABC
DEF 303 | ABC
DEF 304 | ABC
DEF 305 | ABC
DEF 306 | ABC
DEF 307 | ABC
DEF 308 | ABC
DEF 309 | ABC
DEF 310 | ABC
DEF 311 | test 312 | test 313 | test 314 | test 315 | test 316 | test 317 | test 318 | test 319 | test 320 | test 321 | test 322 | test 323 | test 324 | test 325 | test 326 | test 327 | test 328 | test 329 | test 330 | test 331 | test 332 | test 333 | test 334 | test 335 | test 336 | test 337 | test 338 | test 339 | test 340 | test 341 | test 342 | test 343 | test 344 | test 345 | test 346 | test 347 | test 348 | test 349 | test 350 | test 351 | test 352 | test 353 | test 354 | test 355 | test 356 | test 357 | test 358 | test 359 | test 360 | test 361 | test 362 | test 363 | test 364 | test 365 | test 366 | test 367 | test 368 | `"'> 369 | `"'> 370 | `"'> 371 | `"'> 372 | `"'> 373 | `"'> 374 | `"'> 375 | `"'> 376 | `"'> 377 | `"'> 378 | "`'> 379 | "`'> 380 | "`'> 381 | "`'> 382 | "`'> 383 | "`'> 384 | "`'> 385 | "`'> 386 | "`'> 387 | "`'> 388 | "`'> 389 | "`'> 390 | "`'> 391 | "`'> 392 | "`'> 393 | "`'> 394 | "`'> 395 | "`'> 396 | "`'> 397 | "`'> 398 | "`'> 399 | "`'> 400 | "`'> 401 | "`'> 402 | "`'> 403 | "`'> 404 | "`'> 405 | "`'> 406 | "`'> 407 | "`'> 408 | "`'> 409 | "`'> 410 | "`'> 411 | "`'> 412 | "`'> 413 | "`'> 414 | "`'> 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | XXX 450 | 451 | 452 | 453 | <a href=http://foo.bar/#x=`y></a><img alt="`><img src=x:x onerror=javascript:alert(1)></a>"> 454 | <!--[if]><script>javascript:alert(1)</script --> 455 | <!--[if<img src=x onerror=javascript:alert(1)//]> --> 456 | <script src="/\%(jscript)s"></script> 457 | <script src="\\%(jscript)s"></script> 458 | <IMG """><SCRIPT>alert("XSS")</SCRIPT>"> 459 | <IMG SRC=javascript:alert(String.fromCharCode(88,83,83))> 460 | <IMG SRC=# onmouseover="alert('xxs')"> 461 | <IMG SRC= onmouseover="alert('xxs')"> 462 | <IMG onmouseover="alert('xxs')"> 463 | <IMG SRC=javascript:alert('XSS')> 464 | <IMG SRC=javascript:alert('XSS')> 465 | <IMG SRC=javascript:alert('XSS')> 466 | <IMG SRC="jav ascript:alert('XSS');"> 467 | <IMG SRC="jav ascript:alert('XSS');"> 468 | <IMG SRC="jav ascript:alert('XSS');"> 469 | <IMG SRC="jav ascript:alert('XSS');"> 470 | perl -e 'print "<IMG SRC=java\0script:alert(\"XSS\")>";' > out 471 | <IMG SRC="  javascript:alert('XSS');"> 472 | <SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT> 473 | <BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")> 474 | <SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT> 475 | <<SCRIPT>alert("XSS");//<</SCRIPT> 476 | <SCRIPT SRC=http://ha.ckers.org/xss.js?< B > 477 | <SCRIPT SRC=//ha.ckers.org/.j> 478 | <IMG SRC="javascript:alert('XSS')" 479 | <iframe src=http://ha.ckers.org/scriptlet.html < 480 | \";alert('XSS');// 481 | <plaintext> 482 | 483 | # SQL Injection 484 | # 485 | # Strings which can cause a SQL injection if inputs are not sanitized 486 | 487 | 1;DROP TABLE users 488 | 1'; DROP TABLE users-- 1 489 | ' OR 1=1 -- 1 490 | ' OR '1'='1 491 | 492 | # Server Code Injection 493 | # 494 | # Strings which can cause user to run code on server as a privileged user (c.f. https://news.ycombinator.com/item?id=7665153) 495 | 496 | - 497 | -- 498 | --version 499 | --help 500 | $USER 501 | /dev/null; touch /tmp/blns.fail ; echo 502 | `touch /tmp/blns.fail` 503 | $(touch /tmp/blns.fail) 504 | @{[system "touch /tmp/blns.fail"]} 505 | 506 | # Command Injection (Ruby) 507 | # 508 | # Strings which can call system commands within Ruby/Rails applications 509 | 510 | eval("puts 'hello world'") 511 | System("ls -al /") 512 | `ls -al /` 513 | Kernel.exec("ls -al /") 514 | Kernel.exit(1) 515 | %x('ls -al /') 516 | 517 | # XXE Injection (XML) 518 | # 519 | # String which can reveal system files when parsed by a badly configured XML parser 520 | 521 | <?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE foo [ <!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo> 522 | 523 | # Unwanted Interpolation 524 | # 525 | # Strings which can be accidentally expanded into different strings if evaluated in the wrong context, e.g. used as a printf format string or via Perl or shell eval. Might expose sensitive data from the program doing the interpolation, or might just represent the wrong string. 526 | 527 | $HOME 528 | $ENV{'HOME'} 529 | %d 530 | %s 531 | %*.*s 532 | 533 | # File Inclusion 534 | # 535 | # Strings which can cause user to pull in files that should not be a part of a web server 536 | 537 | ../../../../../../../../../../../etc/passwd%00 538 | ../../../../../../../../../../../etc/hosts 539 | 540 | # Known CVEs and Vulnerabilities 541 | # 542 | # Strings that test for known vulnerabilities 543 | 544 | () { 0; }; touch /tmp/blns.shellshock1.fail; 545 | () { _; } >_[$($())] { touch /tmp/blns.shellshock2.fail; } 546 | 547 | # MSDOS/Windows Special Filenames 548 | # 549 | # Strings which are reserved characters in MSDOS/Windows 550 | 551 | CON 552 | PRN 553 | AUX 554 | CLOCK$ 555 | NUL 556 | A: 557 | ZZ: 558 | COM1 559 | LPT1 560 | LPT2 561 | LPT3 562 | COM2 563 | COM3 564 | COM4 565 | 566 | # Scunthorpe Problem 567 | # 568 | # Innocuous strings which may be blocked by profanity filters (https://en.wikipedia.org/wiki/Scunthorpe_problem) 569 | 570 | Scunthorpe General Hospital 571 | Penistone Community Church 572 | Lightwater Country Park 573 | Jimmy Clitheroe 574 | Horniman Museum 575 | shitake mushrooms 576 | RomansInSussex.co.uk 577 | http://www.cum.qc.ca/ 578 | Craig Cockburn, Software Specialist 579 | Linda Callahan 580 | Dr. Herman I. Libshitz 581 | magna cum laude 582 | Super Bowl XXX 583 | medieval erection of parapets 584 | evaluate 585 | mocha 586 | expression 587 | Arsenal canal 588 | classic 589 | Tyson Gay 590 | 591 | # Human injection 592 | # 593 | # Strings which may cause human to reinterpret worldview 594 | 595 | If you're reading this, you've been in a coma for almost 20 years now. We're trying a new technique. We don't know where this message will end up in your dream, but we hope it works. Please wake up, we miss you. 596 | 597 | # Terminal escape codes 598 | # 599 | # Strings which punish the fools who use cat/type on this file 600 | 601 | Roses are red, violets are blue. Hope you enjoy terminal hue 602 | But now...for my greatest trick... 603 | The quick brown fox... [Beeeep] 604 | 605 | # iOS Vulnerability 606 | # 607 | # Strings which crashed iMessage in iOS versions 8.3 and earlier 608 | 609 | Powerلُلُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ冗 610 | -------------------------------------------------------------------------------- /src/SimpleValidator/Extensions/ExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | using SimpleValidator.Interfaces; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Linq.Expressions; 7 | using System.Text; 8 | using System.Text.RegularExpressions; 9 | 10 | namespace SimpleValidator.Extensions 11 | { 12 | /// <summary> 13 | /// Always use the positive route i.e. a true result should indicate validity therefore generally prefix with "Is" 14 | /// e.g. This field is not zero 15 | /// </summary> 16 | public static class ExtensionMethods 17 | { 18 | #region " String " 19 | 20 | #region " Nullable, Empty & Whitespace " 21 | 22 | /// <summary> 23 | /// This is simply a shorthand method "!string.IsNullOrEmpty(value)" 24 | /// </summary> 25 | /// <param name="value">The string to check.</param> 26 | /// <returns>true is the value is not null or it's length != 0</returns> 27 | public static bool IsNotNullOrEmpty(this string value) 28 | { 29 | return !string.IsNullOrEmpty(value); 30 | } 31 | 32 | /// <summary> 33 | /// Inverse of <see cref="IsNotNullOrEmpty"/> method 34 | /// </summary> 35 | /// <param name="value"></param> 36 | /// <returns></returns> 37 | public static bool IsNullOrEmpty(this string value) 38 | { 39 | return !value.IsNotNullOrEmpty(); 40 | } 41 | 42 | /// <summary> 43 | /// This is simply a shorthand method "!string.IsNullOrEmpty(value)" 44 | /// </summary> 45 | /// <param name="value">The string to check.</param> 46 | /// <returns>true is the value is not null or it's length != 0</returns> 47 | public static bool IsNotNullOrWhiteSpace(this string value) 48 | { 49 | return !string.IsNullOrWhiteSpace(value); 50 | } 51 | 52 | /// <summary> 53 | /// Inverse of <see cref="IsNotNullOrWhiteSpace"/> method 54 | /// </summary> 55 | /// <param name="value"></param> 56 | /// <returns></returns> 57 | public static bool IsNullOrWhiteSpace(this string value) 58 | { 59 | return !value.IsNotNullOrWhiteSpace(); 60 | } 61 | 62 | #endregion 63 | 64 | #region " Lengths " 65 | 66 | /// <summary> 67 | /// Checks if this string is between the min and max values (inclusive) 68 | /// </summary> 69 | /// <param name="value"></param> 70 | /// <param name="min">Inclusive min length</param> 71 | /// <param name="max">Inclusive max length</param> 72 | /// <returns></returns> 73 | public static bool IsBetweenLength(this string value, int min, int max) 74 | { 75 | if (value.IsNull() && min == 0) 76 | { 77 | return true; // if it's null it has length 0 78 | } 79 | else if (value.IsNull()) 80 | { 81 | return false; 82 | } 83 | else 84 | { 85 | return value.Length >= min && value.Length <= max; 86 | } 87 | } 88 | 89 | /// <summary> 90 | /// Checks if the string is at least max characters 91 | /// </summary> 92 | /// <param name="value"></param> 93 | /// <param name="max">Inclusive max length</param> 94 | /// <returns></returns> 95 | public static bool IsMaxLength(this string value, int max) 96 | { 97 | if (value.IsNull()) 98 | { 99 | return true; // if it's null it has length 0 and that has to be less than max 100 | } 101 | else 102 | { 103 | return value.Length <= max; 104 | } 105 | } 106 | 107 | /// <summary> 108 | /// 109 | /// </summary> 110 | /// <param name="value"></param> 111 | /// <param name="min"></param> 112 | /// <returns></returns> 113 | public static bool IsMinLength(this string value, int min) 114 | { 115 | if (value.IsNull() && min == 0) 116 | { 117 | return true; // if it's null it has length 0 118 | } 119 | else if (value.IsNull()) 120 | { 121 | return false; 122 | } 123 | else 124 | { 125 | return value.Length >= min; 126 | } 127 | } 128 | 129 | /// <summary> 130 | /// 131 | /// </summary> 132 | /// <param name="value"></param> 133 | /// <param name="length"></param> 134 | /// <returns></returns> 135 | public static bool IsExactLength(this string value, int length) 136 | { 137 | return value.IsBetweenLength(length, length); 138 | } 139 | 140 | #endregion 141 | 142 | #region " Misc " 143 | 144 | /// <summary> 145 | /// Check if the current value is a valid email address. It uses the following regular expression 146 | /// ^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-||_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+([a-z]+|\d|-|\.{0,1}|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])?([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$ 147 | /// null values will fail. 148 | /// Empty strings will fail. 149 | /// It performs the check from method <see cref="IsNotNullOrEmpty"/> 150 | /// </summary> 151 | /// <param name="value">The value to check</param> 152 | /// <returns>True if the value is a valid email address</returns> 153 | public static bool IsEmail(this string value) 154 | { 155 | if (value.IsNullOrEmpty()) 156 | { 157 | return false; // if it's null it cannot possibly be an email 158 | } 159 | else 160 | { 161 | string exp = @"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-||_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+([a-z]+|\d|-|\.{0,1}|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])?([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$"; 162 | 163 | return new Regex(exp, RegexOptions.IgnoreCase).IsMatch(value); 164 | } 165 | } 166 | 167 | /// <summary> 168 | /// Checks if the current value is a password. The password must be at least 8 characters, at least 1 uppercase character, at least 1 lowercase character, at least one number and a maximum of 30 characters. 169 | /// It uses the following regular expression 170 | /// ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,15}$ 171 | /// </summary> 172 | /// <param name="value"></param> 173 | /// <returns></returns> 174 | public static bool IsPassword(this string value) 175 | { 176 | if (value.IsNullOrEmpty()) 177 | { 178 | return false; // if it's null it cannot possibly be a password 179 | } 180 | else 181 | { 182 | string exp = @"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,30}$"; 183 | 184 | return new Regex(exp, RegexOptions.IgnoreCase).IsMatch(value); 185 | } 186 | } 187 | 188 | /// <summary> 189 | /// Validates if the specified object passes the regular expression provided. If the object is null, it will fail. The method calls ToString on the object to get the string value. 190 | /// </summary> 191 | /// <param name="value">The value to be evaluated</param> 192 | /// <param name="exp">The regular expression</param> 193 | /// <returns></returns> 194 | public static bool IsRegex(this string value, string exp) 195 | { 196 | if (value.IsNotNullOrEmpty()) 197 | { 198 | return false; 199 | } 200 | 201 | string check = value.ToString(); 202 | 203 | return new Regex(exp, RegexOptions.IgnoreCase).IsMatch(check); 204 | } 205 | 206 | /// <summary> 207 | /// Determines if a string is a valid credit card number 208 | /// Taken from https://github.com/JeremySkinner/FluentValidation/blob/master/src/FluentValidation/Validators/CreditCardValidator.cs 209 | /// Uses code from: http://www.beachnet.com/~hstiles/cardtype.html 210 | /// </summary> 211 | /// <param name="value"></param> 212 | /// <returns></returns> 213 | public static bool IsCreditCard(this string value) 214 | { 215 | if (value.IsNotNullOrEmpty()) 216 | { 217 | value = value.Replace("-", "").Replace(" ", ""); 218 | 219 | int checksum = 0; 220 | bool evenDigit = false; 221 | 222 | foreach (char digit in value.ToCharArray().Reverse()) 223 | { 224 | if (!char.IsDigit(digit)) 225 | { 226 | return false; 227 | } 228 | 229 | int digitValue = (digit - '0') * (evenDigit ? 2 : 1); 230 | evenDigit = !evenDigit; 231 | 232 | while (digitValue > 0) 233 | { 234 | checksum += digitValue % 10; 235 | digitValue /= 10; 236 | } 237 | } 238 | 239 | return (checksum % 10) == 0; 240 | } 241 | else 242 | { 243 | return false; // a null or empty string cannot be a valid credit card 244 | } 245 | } 246 | 247 | /// <summary> 248 | /// 249 | /// </summary> 250 | /// <param name="value"></param> 251 | /// <param name="compare"></param> 252 | /// <returns></returns> 253 | public static bool IsEqualTo(this string value, string compare) 254 | { 255 | if (value.IsNull() && compare.IsNull()) 256 | { 257 | return true; 258 | } 259 | if (value.IsNull() || compare.IsNull()) 260 | { 261 | return false; 262 | } 263 | return String.Equals(value, compare, StringComparison.Ordinal); 264 | } 265 | 266 | #endregion 267 | 268 | #endregion 269 | 270 | #region " Object " 271 | 272 | /// <summary> 273 | /// Check if the current object is not equal to null 274 | /// </summary> 275 | /// <param name="value">The object to check</param> 276 | /// <returns>true is the value is not null</returns> 277 | public static bool IsNotNull(this object value) 278 | { 279 | return (value != null); 280 | } 281 | 282 | /// <summary> 283 | /// Inverse of <see cref="IsNotNull"/> method 284 | /// </summary> 285 | /// <param name="value">The object to check</param> 286 | /// <returns>true is the value is null</returns> 287 | public static bool IsNull(this object value) 288 | { 289 | return !value.IsNotNull(); 290 | } 291 | 292 | /// <summary> 293 | /// 294 | /// </summary> 295 | /// <param name="value"></param> 296 | /// <param name="func"></param> 297 | /// <returns></returns> 298 | public static bool Is(this object value, Func<bool> func) 299 | { 300 | return func(); 301 | } 302 | 303 | /// <summary> 304 | /// 305 | /// </summary> 306 | /// <param name="value"></param> 307 | /// <param name="func"></param> 308 | /// <returns></returns> 309 | public static bool IsNot(this object value, Func<bool> func) 310 | { 311 | return !func(); 312 | } 313 | 314 | #region " IsRule " 315 | 316 | /// <summary> 317 | /// Pass in an instance of an object that implements IRule 318 | /// </summary> 319 | /// <param name="value"></param> 320 | /// <param name="rule"></param> 321 | /// <returns></returns> 322 | public static bool IsRule(this object value, IRule rule) 323 | { 324 | return rule.IsValid(); 325 | } 326 | 327 | #endregion 328 | 329 | #endregion 330 | 331 | #region " Integer " 332 | 333 | public static bool IsNotZero(this int value) 334 | { 335 | return (value != 0); 336 | } 337 | 338 | public static bool Is(this int value, int compare) 339 | { 340 | return (value == compare); 341 | } 342 | 343 | public static bool IsGreaterThan(this int value, int min) 344 | { 345 | return (value >= min); 346 | } 347 | 348 | public static bool IsLessThan(this int value, int max) 349 | { 350 | return (value <= max); 351 | } 352 | 353 | public static bool IsBetween(this int value, int min, int max) 354 | { 355 | return (value <= max && value >= min); 356 | } 357 | 358 | #endregion 359 | 360 | #region " DateTime " 361 | 362 | #region " IsDate " 363 | 364 | public static bool IsDate(this object value) 365 | { 366 | return value.IsDate(CultureInfo.InvariantCulture); 367 | } 368 | 369 | public static bool IsDate(this object value, CultureInfo info) 370 | { 371 | return value.IsDate(CultureInfo.InvariantCulture, DateTimeStyles.None); 372 | } 373 | 374 | public static bool IsDate(this object value, CultureInfo info, DateTimeStyles styles) 375 | { 376 | if (value.IsNotNull()) 377 | { 378 | DateTime result; 379 | 380 | if (DateTime.TryParse(value.ToString(), info, styles, out result)) 381 | { 382 | return true; 383 | } 384 | else 385 | { 386 | return false; 387 | } 388 | } 389 | else 390 | { 391 | return false; // if it's null it cannot be a date 392 | } 393 | } 394 | 395 | #endregion 396 | 397 | #region " Date Comparisons " 398 | 399 | public static bool IsGreaterThan(this DateTime value, DateTime compare) 400 | { 401 | return value > compare; 402 | } 403 | 404 | public static bool IsGreaterThanOrEqualTo(this DateTime value, DateTime compare) 405 | { 406 | return value >= compare; 407 | } 408 | 409 | public static bool IsLessThan(this DateTime value, DateTime compare) 410 | { 411 | return value < compare; 412 | } 413 | 414 | public static bool IsLessThanOrEqualTo(this DateTime value, DateTime compare) 415 | { 416 | return value <= compare; 417 | } 418 | 419 | public static bool IsEqualTo(this DateTime value, DateTime compare) 420 | { 421 | return value == compare; 422 | } 423 | 424 | public static bool IsBetweenInclusive(this DateTime value, DateTime from, DateTime to) 425 | { 426 | return value >= from && value <= to; 427 | } 428 | 429 | public static bool IsBetweenExclusive(this DateTime value, DateTime from, DateTime to) 430 | { 431 | return value > from && value < to; 432 | } 433 | 434 | #endregion 435 | 436 | #endregion 437 | 438 | #region " Helpers " 439 | 440 | public static string EmptyStringIfNull(this string value) 441 | { 442 | if (value.IsNull()) 443 | { 444 | return string.Empty; 445 | } 446 | else 447 | { 448 | return value; 449 | } 450 | } 451 | 452 | #endregion 453 | 454 | #region " GetName " 455 | 456 | // Code taken from http://joelabrahamsson.com/getting-property-and-method-names-using-static-reflection-in-c/ 457 | 458 | public static string GetName<T>(this T instance, Expression<Func<T, object>> expression) 459 | { 460 | return GetName(expression); 461 | } 462 | 463 | public static string GetName<T>(Expression<Func<T, object>> expression) 464 | { 465 | if (expression == null) 466 | { 467 | throw new ArgumentException( 468 | "The expression cannot be null."); 469 | } 470 | 471 | return GetName(expression.Body); 472 | } 473 | 474 | public static string GetName<T>(this T instance, Expression<Action<T>> expression) 475 | { 476 | return GetName(expression); 477 | } 478 | 479 | public static string GetName<T>(Expression<Action<T>> expression) 480 | { 481 | if (expression == null) 482 | { 483 | throw new ArgumentException( 484 | "The expression cannot be null."); 485 | } 486 | 487 | return GetName(expression.Body); 488 | } 489 | 490 | private static string GetName(Expression expression) 491 | { 492 | if (expression == null) 493 | { 494 | throw new ArgumentException( 495 | "The expression cannot be null."); 496 | } 497 | 498 | if (expression is MemberExpression) 499 | { 500 | // Reference type property or field 501 | var memberExpression = 502 | (MemberExpression)expression; 503 | return memberExpression.Member.Name; 504 | } 505 | 506 | if (expression is MethodCallExpression) 507 | { 508 | // Reference type method 509 | var methodCallExpression = 510 | (MethodCallExpression)expression; 511 | return methodCallExpression.Method.Name; 512 | } 513 | 514 | if (expression is UnaryExpression) 515 | { 516 | // Property, field of method returning value type 517 | var unaryExpression = (UnaryExpression)expression; 518 | return GetName(unaryExpression); 519 | } 520 | 521 | throw new ArgumentException("Invalid expression"); 522 | } 523 | 524 | private static string GetName(UnaryExpression unaryExpression) 525 | { 526 | if (unaryExpression.Operand is MethodCallExpression) 527 | { 528 | var methodExpression = 529 | (MethodCallExpression)unaryExpression.Operand; 530 | return methodExpression.Method.Name; 531 | } 532 | 533 | return ((MemberExpression)unaryExpression.Operand) 534 | .Member.Name; 535 | } 536 | 537 | #endregion 538 | 539 | #region " Type Test " 540 | 541 | public static bool Is<T>(this object value) 542 | { 543 | if (value == null) 544 | { 545 | return false; 546 | } 547 | 548 | var converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T)); 549 | 550 | try 551 | { 552 | T result = (T)converter.ConvertFromString(value.ToString()); 553 | return result != null; 554 | } 555 | catch (Exception) 556 | { 557 | return false; 558 | } 559 | } 560 | 561 | public static bool IsInt(this object value) 562 | { 563 | return value.Is<int>(); 564 | } 565 | 566 | public static bool IsShort(this object value) 567 | { 568 | return value.Is<short>(); 569 | } 570 | 571 | public static bool IsLong(this object value) 572 | { 573 | return value.Is<long>(); 574 | } 575 | 576 | public static bool IsDouble(this object value) 577 | { 578 | return value.Is<Double>(); 579 | } 580 | 581 | public static bool IsDecimal(this object value) 582 | { 583 | return value.Is<Decimal>(); 584 | } 585 | 586 | public static bool IsBool(this object value) 587 | { 588 | return value.Is<bool>(); 589 | } 590 | 591 | public static bool IsNumber(this object value) 592 | { 593 | return 594 | value.IsLong() || 595 | value.IsDouble() || 596 | value.IsDecimal() || 597 | value.IsDouble(); 598 | } 599 | 600 | #endregion 601 | 602 | #region " To " 603 | 604 | public static T To<T>(this object value) 605 | { 606 | return value.To<T>(default(T)); 607 | } 608 | 609 | public static T To<T>(this object value, T fallback) 610 | { 611 | if (value == null) 612 | { 613 | return fallback; 614 | } 615 | 616 | var converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T)); 617 | if (converter != null) 618 | { 619 | try 620 | { 621 | return (T)converter.ConvertFromString(value.ToString()); 622 | } 623 | catch (Exception) 624 | { 625 | return fallback; 626 | } 627 | 628 | } 629 | return fallback; 630 | } 631 | 632 | public static int ToInt(this object value, int fallback = default(int)) 633 | { 634 | return value.To<int>(fallback); 635 | } 636 | 637 | public static short ToShort(this object value, short fallback = default(short)) 638 | { 639 | return value.To<short>(fallback); 640 | } 641 | 642 | public static long ToLong(this object value, long fallback = default(long)) 643 | { 644 | return value.To<long>(fallback); 645 | } 646 | 647 | public static double ToDouble(this object value, double fallback = default(double)) 648 | { 649 | return value.To<double>(fallback); 650 | } 651 | 652 | public static decimal ToDecimal(this object value, decimal fallback = default(decimal)) 653 | { 654 | return value.To<decimal>(fallback); 655 | } 656 | 657 | public static bool ToBool(this object value, bool fallback = default(bool)) 658 | { 659 | return value.To<bool>(fallback); 660 | } 661 | 662 | #endregion 663 | } 664 | } --------------------------------------------------------------------------------