├── .editorconfig ├── .github └── workflows │ ├── build.yml │ └── publish.yml ├── .gitignore ├── Directory.Build.Props ├── LICENSE.md ├── README.md ├── Throw.sln ├── assets ├── getting-started.png ├── icon-square.png └── icon.png ├── src ├── Common │ ├── ExceptionCustomizations.cs │ ├── ExceptionThrower.cs │ └── Validatable.cs ├── Properties │ └── AssemblyInfo.cs ├── Throw.csproj ├── ValidatableCreation │ ├── ValidatableCreationExtensions.Nullables.cs │ └── ValidatableCreationExtensions.cs ├── ValidatableExtensions │ ├── StringProperties │ │ ├── ValidatableExtensions.StringProperties.Equality.cs │ │ ├── ValidatableExtensions.StringProperties.Length.cs │ │ ├── ValidatableExtensions.StringProperties.Regex.cs │ │ └── ValidatableExtensions.StringProperties.Substring.cs │ ├── Strings │ │ ├── ValidatableExtensions.Strings.Equality.cs │ │ ├── ValidatableExtensions.Strings.Length.cs │ │ ├── ValidatableExtensions.Strings.Regex.cs │ │ └── ValidatableExtensions.Strings.Substring.cs │ ├── ValidatableExtensions.BooleanProperties.cs │ ├── ValidatableExtensions.Booleans.cs │ ├── ValidatableExtensions.CollectionProperties.cs │ ├── ValidatableExtensions.Collections.cs │ ├── ValidatableExtensions.ComparableProperties.cs │ ├── ValidatableExtensions.Comparables.cs │ ├── ValidatableExtensions.ConditionalCompilation.cs │ ├── ValidatableExtensions.DateTimeProperties.cs │ ├── ValidatableExtensions.DateTimes.cs │ ├── ValidatableExtensions.EnumProperties.cs │ ├── ValidatableExtensions.Enums.cs │ ├── ValidatableExtensions.Equalities.cs │ ├── ValidatableExtensions.EqualityProperties.cs │ ├── ValidatableExtensions.UriProperties.cs │ └── ValidatalbeExtensions.Uris.cs ├── ValidatableMethods │ └── ValidatableMethods.Types.cs ├── Validators │ ├── Validator.Collections.cs │ ├── Validator.Comperables.cs │ ├── Validator.DateTimes.cs │ ├── Validator.Enums.cs │ ├── Validator.Equalities.cs │ ├── Validator.Strings.cs │ ├── Validator.Types.cs │ └── Validator.Uris.cs ├── _usings.cs └── stylecop.json └── tests └── UnitTests ├── .editorconfig ├── Common ├── ExceptionThrowerTests.cs └── ValidatableTests.cs ├── Throw.UnitTests.csproj ├── Utils └── ParameterConstants.cs ├── ValidatableCreation ├── ValidatableCreationExtensions.NullablesTests.cs └── ValidatableCreationExtensionsTests.cs ├── ValidatableExtensions ├── StringProperties │ ├── ValidatableExtensions.StringProperties.EqualityTests.cs │ ├── ValidatableExtensions.StringProperties.LengthTests.cs │ ├── ValidatableExtensions.StringProperties.RegexTests.cs │ └── ValidatableExtensions.StringProperties.SubstringTests.cs ├── Strings │ ├── ValidatableExtensions.Strings.EqualityTests.cs │ ├── ValidatableExtensions.Strings.LengthTests.cs │ ├── ValidatableExtensions.Strings.RegexTests.cs │ └── ValidatableExtensions.Strings.SubstringTests.cs ├── ValidatableExtensions.BooleanPropertiesTests.cs ├── ValidatableExtensions.BooleansTests.cs ├── ValidatableExtensions.CollectionPropertiesTests.cs ├── ValidatableExtensions.CollectionsTests.cs ├── ValidatableExtensions.ComparablePropertiesTests.cs ├── ValidatableExtensions.ComparablesTests.cs ├── ValidatableExtensions.ConditionalCompilationTests.cs ├── ValidatableExtensions.DateTimePropertiesTests.cs ├── ValidatableExtensions.DateTimesTests.cs ├── ValidatableExtensions.EnumPropertiesTests.cs ├── ValidatableExtensions.EnumsTests.cs ├── ValidatableExtensions.EqualitiesTests.cs ├── ValidatableExtensions.EqualityPropertiesTests.cs ├── ValidatableExtensions.UriPropertiesTests.cs └── ValidatableExtensions.UrisTests.cs ├── ValidatableMethods └── ValidatableMethods.TypesTests.cs ├── Validators └── Validator.CollectionsTests.cs └── _usings.cs /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = crlf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | # SA1615: Element return value should be documented. 12 | dotnet_diagnostic.SA1615.severity = none 13 | 14 | # SA1611: Element parameters must be documented. 15 | dotnet_diagnostic.SA1611.severity = none 16 | 17 | # SA1633: File must have header. 18 | dotnet_diagnostic.SA1633.severity = none 19 | 20 | # SA1633: Generic type parameters must be documented. 21 | dotnet_diagnostic.SA1618.severity = none 22 | 23 | # SA1133: Each attribute should be placed in its own set of square brackets. 24 | dotnet_diagnostic.SA1133.severity = none 25 | 26 | # SA1600: Elements must be documented. 27 | dotnet_diagnostic.SA1600.severity = none 28 | 29 | # SA1601: Partial elementes should be documented. 30 | dotnet_diagnostic.SA1601.severity = none 31 | 32 | # SA1313: Parameter names must begin with lower case letter. 33 | dotnet_diagnostic.SA1313.severity = none 34 | 35 | # SA1009: Closing parenthesis should be followed by a space. 36 | dotnet_diagnostic.SA1009.severity = none 37 | 38 | # SA1000: The keyword 'new' should be followed by a space. 39 | dotnet_diagnostic.SA1000.severity = none 40 | 41 | # IDE0008: Use explicit type 42 | csharp_style_var_when_type_is_apparent = true 43 | 44 | # IDE0130: Namespace does not match folder structure 45 | dotnet_style_namespace_match_folder = false 46 | 47 | # IDE0023: Use block body for operators 48 | csharp_style_expression_bodied_operators = when_on_single_line 49 | 50 | # IDE0130: Namespace does not match folder structure 51 | dotnet_diagnostic.IDE0130.severity = none 52 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: windows-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Setup .NET 17 | uses: actions/setup-dotnet@v1 18 | with: 19 | dotnet-version: 6.0.x 20 | - name: Restore dependencies 21 | run: dotnet restore 22 | - name: Build 23 | run: dotnet build -c Release --no-restore 24 | - name: Test Debug 25 | run: dotnet test -c Debug --no-restore --verbosity normal --collect:"XPlat Code Coverage" 26 | - name: Test Release 27 | run: dotnet test -c Release --no-restore --verbosity normal --collect:"XPlat Code Coverage" 28 | - name: Upload coverage to Codecov 29 | uses: codecov/codecov-action@v1 30 | with: 31 | token: ${{ secrets.CODE_COV_TOKEN }} 32 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish Throw to nuget 2 | on: 3 | workflow_dispatch: 4 | push: 5 | branches: 6 | - main # Default release branch 7 | paths: 8 | - 'src/**' 9 | jobs: 10 | publish: 11 | name: build, pack & publish 12 | runs-on: windows-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Setup dotnet 17 | uses: actions/setup-dotnet@v1 18 | with: 19 | dotnet-version: 6.0.x 20 | 21 | # Publish 22 | - name: Package 23 | run: dotnet pack -c Release src\Throw.csproj 24 | - name: Publish 25 | run: dotnet nuget push artifacts\*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/.ionide 2 | **/.vscode 3 | **/.vs 4 | **/.idea 5 | **/obj 6 | **/bin 7 | **/artifacts 8 | **/TestResults 9 | 10 | .fake 11 | .ionide 12 | 13 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 14 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 15 | 16 | # User-specific stuff 17 | .idea/**/workspace.xml 18 | .idea/**/tasks.xml 19 | .idea/**/usage.statistics.xml 20 | .idea/**/dictionaries 21 | .idea/**/shelf 22 | 23 | # AWS User-specific 24 | .idea/**/aws.xml 25 | 26 | # Generated files 27 | .idea/**/contentModel.xml 28 | 29 | # Sensitive or high-churn files 30 | .idea/**/dataSources/ 31 | .idea/**/dataSources.ids 32 | .idea/**/dataSources.local.xml 33 | .idea/**/sqlDataSources.xml 34 | .idea/**/dynamic.xml 35 | .idea/**/uiDesigner.xml 36 | .idea/**/dbnavigator.xml 37 | 38 | # Gradle 39 | .idea/**/gradle.xml 40 | .idea/**/libraries 41 | 42 | # Gradle and Maven with auto-import 43 | # When using Gradle or Maven with auto-import, you should exclude module files, 44 | # since they will be recreated, and may cause churn. Uncomment if using 45 | # auto-import. 46 | # .idea/artifacts 47 | # .idea/compiler.xml 48 | # .idea/jarRepositories.xml 49 | # .idea/modules.xml 50 | # .idea/*.iml 51 | # .idea/modules 52 | # *.iml 53 | # *.ipr 54 | 55 | # CMake 56 | cmake-build-*/ 57 | 58 | # Mongo Explorer plugin 59 | .idea/**/mongoSettings.xml 60 | 61 | # File-based project format 62 | *.iws 63 | 64 | # IntelliJ 65 | out/ 66 | 67 | # mpeltonen/sbt-idea plugin 68 | .idea_modules/ 69 | 70 | # JIRA plugin 71 | atlassian-ide-plugin.xml 72 | 73 | # Cursive Clojure plugin 74 | .idea/replstate.xml 75 | 76 | # SonarLint plugin 77 | .idea/sonarlint/ 78 | 79 | # Crashlytics plugin (for Android Studio and IntelliJ) 80 | com_crashlytics_export_strings.xml 81 | crashlytics.properties 82 | crashlytics-build.properties 83 | fabric.properties 84 | 85 | # Editor-based Rest Client 86 | .idea/httpRequests 87 | 88 | # Android studio 3.1+ serialized cache file 89 | .idea/caches/build_file_checksums.ser 90 | -------------------------------------------------------------------------------- /Directory.Build.Props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | true 7 | net6.0 8 | enable 9 | enable 10 | True 11 | true 12 | 13 | 14 | 15 | 16 | all 17 | runtime; build; native; contentfiles; analyzers 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Amichai Mantinband 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Throw.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32519.111 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Throw", "src\Throw.csproj", "{EFF12011-026D-48E3-9EEE-5F1B5C2D0FFC}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0289805B-A7C8-441D-BD46-C05D135FAD23}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Throw.UnitTests", "tests\UnitTests\Throw.UnitTests.csproj", "{FB6525E8-E040-4F68-9152-548C6D64EEAB}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".sln", ".sln", "{78F97BB4-8243-479B-81C4-887AB3B173B5}" 13 | ProjectSection(SolutionItems) = preProject 14 | .editorconfig = .editorconfig 15 | .gitignore = .gitignore 16 | Directory.Build.Props = Directory.Build.Props 17 | LICENSE.md = LICENSE.md 18 | README.md = README.md 19 | EndProjectSection 20 | EndProject 21 | Global 22 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 23 | Debug|Any CPU = Debug|Any CPU 24 | Release|Any CPU = Release|Any CPU 25 | EndGlobalSection 26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 27 | {EFF12011-026D-48E3-9EEE-5F1B5C2D0FFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {EFF12011-026D-48E3-9EEE-5F1B5C2D0FFC}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {EFF12011-026D-48E3-9EEE-5F1B5C2D0FFC}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {EFF12011-026D-48E3-9EEE-5F1B5C2D0FFC}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {FB6525E8-E040-4F68-9152-548C6D64EEAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {FB6525E8-E040-4F68-9152-548C6D64EEAB}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {FB6525E8-E040-4F68-9152-548C6D64EEAB}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {FB6525E8-E040-4F68-9152-548C6D64EEAB}.Release|Any CPU.Build.0 = Release|Any CPU 35 | EndGlobalSection 36 | GlobalSection(SolutionProperties) = preSolution 37 | HideSolutionNode = FALSE 38 | EndGlobalSection 39 | GlobalSection(NestedProjects) = preSolution 40 | {FB6525E8-E040-4F68-9152-548C6D64EEAB} = {0289805B-A7C8-441D-BD46-C05D135FAD23} 41 | EndGlobalSection 42 | GlobalSection(ExtensibilityGlobals) = postSolution 43 | SolutionGuid = {3FBC4496-672C-438E-923F-79A855956FEC} 44 | EndGlobalSection 45 | EndGlobal 46 | -------------------------------------------------------------------------------- /assets/getting-started.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amantinband/throw/b559d6f99a233e193ab21e0b01d8841a61ae4a22/assets/getting-started.png -------------------------------------------------------------------------------- /assets/icon-square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amantinband/throw/b559d6f99a233e193ab21e0b01d8841a61ae4a22/assets/icon-square.png -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amantinband/throw/b559d6f99a233e193ab21e0b01d8841a61ae4a22/assets/icon.png -------------------------------------------------------------------------------- /src/Common/ExceptionCustomizations.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// The exception customizations. 5 | /// Contains a discriminated union of all possible exception customization options. 6 | /// 7 | public struct ExceptionCustomizations 8 | { 9 | /// 10 | /// Initializes a new instance of the struct. 11 | /// 12 | public ExceptionCustomizations(OneOf, Func> customization) 13 | { 14 | this.Customization = customization; 15 | } 16 | 17 | /// 18 | /// Gets a discriminated union of all possible exception customization options. 19 | /// 20 | public OneOf, Func> Customization { get; } 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// The customization will be the given . 25 | /// 26 | public static implicit operator ExceptionCustomizations(string message) => new(message); 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// The customization will be an exception of the given . 31 | /// 32 | public static implicit operator ExceptionCustomizations(Type type) => new(type); 33 | 34 | /// 35 | /// Initializes a new instance of the class. 36 | /// The customization will be the given exception returning . 37 | /// 38 | public static implicit operator ExceptionCustomizations(Func func) => new(func); 39 | 40 | /// 41 | /// Initializes a new instance of the class. 42 | /// The customization will be the given exception returning . 43 | /// 44 | public static implicit operator ExceptionCustomizations(Func func) => new(func); 45 | 46 | /// 47 | /// Initializes a new instance of the class. 48 | /// The customization will match the given . 49 | /// 50 | public static implicit operator ExceptionCustomizations(OneOf, Func> customizations) => new(customizations); 51 | } -------------------------------------------------------------------------------- /src/Common/ExceptionThrower.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Exception throwing extensions. 5 | /// 6 | public static class ExceptionThrower 7 | { 8 | /// 9 | /// Throws an , unless the defines a custom exception. 10 | /// 11 | [DoesNotReturn, MethodImpl(MethodImplOptions.AggressiveInlining)] 12 | public static void ThrowNull( 13 | string paramName, 14 | ExceptionCustomizations? exceptionCustomizations = null, 15 | string? generalMessage = "Value cannot be null.") 16 | { 17 | if (exceptionCustomizations is null) 18 | { 19 | throw new ArgumentNullException(paramName: paramName, message: generalMessage); 20 | } 21 | 22 | throw exceptionCustomizations.Value.Customization.Match( 23 | message => new ArgumentNullException(paramName: paramName, message: message ?? generalMessage), 24 | type => (Exception)Activator.CreateInstance(type)!, 25 | func => func(), 26 | func => func(paramName)); 27 | } 28 | 29 | /// 30 | /// Throws an , unless the defines a custom exception. 31 | /// 32 | [DoesNotReturn, MethodImpl(MethodImplOptions.AggressiveInlining)] 33 | public static void ThrowOutOfRange( 34 | string paramName, 35 | TValue actualValue, 36 | ExceptionCustomizations? exceptionCustomizations = null, 37 | string? generalMessage = "Specified argument was out of the range of valid values.") 38 | { 39 | if (exceptionCustomizations is null) 40 | { 41 | throw new ArgumentOutOfRangeException(paramName: paramName, actualValue, message: generalMessage); 42 | } 43 | 44 | throw exceptionCustomizations.Value.Customization.Match( 45 | message => new ArgumentOutOfRangeException(paramName: paramName, actualValue, message: message ?? generalMessage), 46 | type => (Exception)Activator.CreateInstance(type)!, 47 | func => func(), 48 | func => func(paramName)); 49 | } 50 | 51 | /// 52 | /// Throws an , unless the defines a custom exception. 53 | /// 54 | [DoesNotReturn, MethodImpl(MethodImplOptions.AggressiveInlining)] 55 | public static void Throw( 56 | string paramName, 57 | ExceptionCustomizations? exceptionCustomizations = null, 58 | string? generalMessage = null) 59 | { 60 | if (exceptionCustomizations is null) 61 | { 62 | throw new ArgumentException(message: generalMessage, paramName: paramName); 63 | } 64 | 65 | throw exceptionCustomizations.Value.Customization.Match( 66 | message => new ArgumentException(message: message ?? generalMessage, paramName: paramName), 67 | type => (Exception)Activator.CreateInstance(type)!, 68 | func => func(), 69 | func => func(paramName)); 70 | } 71 | } -------------------------------------------------------------------------------- /src/Common/Validatable.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Creates a new instance with the specified value. 5 | /// The instance can be used to throw exceptions if the value matches a condition specified. 6 | /// 7 | /// The value to be validated. 8 | /// The name of the parameter holding the . 9 | /// Customizations to the exception, which will be applied if an exception is thrown. 10 | [SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:Prefix local calls with this", Justification = "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3201: SA1101 shows on 'with' expressions")] 11 | public readonly partial record struct Validatable(TValue Value, string ParamName, ExceptionCustomizations? ExceptionCustomizations = null) 12 | where TValue : notnull 13 | { 14 | /// 15 | /// Implicit conversion operator back to the original value's type. 16 | /// 17 | public static implicit operator TValue([DisallowNull] Validatable validatable) => validatable.Value; 18 | 19 | /// 20 | /// Creates a validatable with the specified exception customization. 21 | /// 22 | /// A custom exception message which will be used instead of the default message. 23 | public Validatable Throw([DisallowNull] string message) => 24 | this with { ExceptionCustomizations = message }; 25 | 26 | /// 27 | /// Creates a validatable with the specified exception customization. 28 | /// 29 | /// 30 | /// A function which returns an excpetion. This function will be used to create the exception that will 31 | /// be thrown if a condition is matched. 32 | /// 33 | public Validatable Throw([DisallowNull] Func exceptionThrower) => 34 | this with { ExceptionCustomizations = exceptionThrower }; 35 | 36 | /// 37 | /// Creates a validatable with the specified exception customization. 38 | /// 39 | /// 40 | /// A function which receives the parameter name returns an excpetion. 41 | /// This function will be used to create the exception that will be thrown if a condition is matched. 42 | /// For example: paramName => throw new Exception($"Parameter name: {paramName}"). 43 | /// 44 | public Validatable Throw([DisallowNull] Func exceptionThrower) => 45 | this with { ExceptionCustomizations = exceptionThrower }; 46 | 47 | /// 48 | /// Creates a validatable with the specified exception customization. 49 | /// 50 | /// The type of the exception to be thrown. 51 | public Validatable Throw() 52 | where TException : notnull, Exception, new() => this with { ExceptionCustomizations = typeof(TException) }; 53 | 54 | /// 55 | /// Creates a validatable with the no customizations. 56 | /// 57 | public Validatable Throw() => this with { ExceptionCustomizations = null }; 58 | } 59 | -------------------------------------------------------------------------------- /src/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | [assembly: InternalsVisibleTo("Throw.UnitTests")] 2 | -------------------------------------------------------------------------------- /src/Throw.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Throw 5 | 1.4.0 6 | Amichai Mantinband 7 | icon-square.png 8 | argument,guard,clause,exception,contract,assert,assertions,validation 9 | A simple, fluent, extensible, and fully customizable library for throwing exceptions using .NET 6+ 10 | https://github.com/amantinband/throw 11 | git 12 | https://opensource.org/licenses/MIT 13 | https://github.com/amantinband/throw 14 | ../artifacts/ 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/ValidatableCreation/ValidatableCreationExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extensions for creating s. 5 | /// 6 | public static partial class ValidatableCreationExtensions 7 | { 8 | /// 9 | /// Creates a new instance with the specified value. 10 | /// The instance can be used to throw exceptions if the value matches a condition specified. 11 | /// 12 | /// The value to be validated. 13 | /// A function which returns an excpetion. This function will be used to create the exception that will be thrown if a condition is matched. 14 | /// Doesn't need to be specified. Will be populated by the compiler. 15 | /// 16 | /// This extension method is intended for non-nullable types. 17 | /// For nullable types, use the extension method. 18 | /// 19 | [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] 20 | public static Validatable Throw( 21 | [DisallowNull, NotNull] this TValue value, 22 | Func exceptionThrower, 23 | [CallerArgumentExpression("value")] string? paramName = null) 24 | where TValue : notnull => new(value, paramName!, exceptionThrower); 25 | 26 | /// 27 | /// Creates a new instance with the specified value. 28 | /// The instance can be used to throw exceptions if the value matches a condition specified. 29 | /// 30 | /// The value to be validated. 31 | /// 32 | /// A function which receives the parameter name returns an excpetion. 33 | /// This function will be used to create the exception that will be thrown if a condition is matched. 34 | /// For example: paramName => throw new Exception($"Parameter name: {paramName}"). 35 | /// 36 | /// Doesn't need to be specified. Will be populated by the compiler. 37 | /// 38 | /// This extension method is intended for non-nullable types. 39 | /// For nullable types, use the extension method. 40 | /// 41 | [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] 42 | public static Validatable Throw( 43 | [DisallowNull, NotNull] this TValue value, 44 | Func exceptionThrower, 45 | [CallerArgumentExpression("value")] string? paramName = null) 46 | where TValue : notnull => new(value, paramName!, exceptionThrower); 47 | 48 | /// 49 | /// Creates a new instance with the specified value. 50 | /// The instance can be used to throw exceptions if the value matches a condition specified. 51 | /// 52 | /// The value to be validated. 53 | /// Exception customizations. This can be used to supply a custom exception message which will be used instead of the default message. 54 | /// Doesn't need to be specified. Will be populated by the compiler. 55 | /// 56 | /// This extension method is intended for non-nullable types. 57 | /// For nullable types, use the extension method. 58 | /// 59 | [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] 60 | public static Validatable Throw( 61 | [DisallowNull, NotNull] this TValue value, 62 | ExceptionCustomizations? exceptionCustomizations = null, 63 | [CallerArgumentExpression("value")] string? paramName = null) 64 | where TValue : notnull => new(value, paramName!, exceptionCustomizations); 65 | } 66 | -------------------------------------------------------------------------------- /src/ValidatableExtensions/StringProperties/ValidatableExtensions.StringProperties.Length.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extension methods for string properties. 5 | /// 6 | public static partial class ValidatableExtensions 7 | { 8 | /// 9 | /// Throws an exception if the string returned from the given is longer than characters. 10 | /// 11 | /// 12 | /// The default exception thrown is an . 13 | /// 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public static ref readonly Validatable IfLongerThan( 16 | this in Validatable validatable, 17 | Func func, 18 | int length, 19 | [CallerArgumentExpression("func")] string? funcName = null) 20 | where TValue : notnull 21 | { 22 | Validator.ThrowIfLongerThan( 23 | func(validatable.Value), 24 | $"{validatable.ParamName}: {funcName}", 25 | validatable.ExceptionCustomizations, 26 | length); 27 | 28 | return ref validatable; 29 | } 30 | 31 | /// 32 | /// Throws an exception if the string returned from the given is shorter than characters. 33 | /// 34 | /// 35 | /// The default exception thrown is an . 36 | /// 37 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 38 | public static ref readonly Validatable IfShorterThan( 39 | this in Validatable validatable, 40 | Func func, 41 | int length, 42 | [CallerArgumentExpression("func")] string? funcName = null) 43 | where TValue : notnull 44 | { 45 | Validator.ThrowIfShorterThan( 46 | func(validatable.Value), 47 | $"{validatable.ParamName}: {funcName}", 48 | validatable.ExceptionCustomizations, 49 | length); 50 | 51 | return ref validatable; 52 | } 53 | 54 | /// 55 | /// Throws an exception if the length of string returned from the given is equal to . 56 | /// 57 | /// 58 | /// The default exception thrown is an . 59 | /// 60 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 61 | public static ref readonly Validatable IfLengthEquals( 62 | this in Validatable validatable, 63 | Func func, 64 | int length, 65 | [CallerArgumentExpression("func")] string? funcName = null) 66 | where TValue : notnull 67 | { 68 | Validator.ThrowIfLengthEquals( 69 | func(validatable.Value), 70 | $"{validatable.ParamName}: {funcName}", 71 | validatable.ExceptionCustomizations, 72 | length); 73 | 74 | return ref validatable; 75 | } 76 | 77 | /// 78 | /// Throws an exception if the length of string returned from the given is not equal to . 79 | /// 80 | /// 81 | /// The default exception thrown is an . 82 | /// 83 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 84 | public static ref readonly Validatable IfLengthNotEquals( 85 | this in Validatable validatable, 86 | Func func, 87 | int length, 88 | [CallerArgumentExpression("func")] string? funcName = null) 89 | where TValue : notnull 90 | { 91 | Validator.ThrowIfLengthNotEquals( 92 | func(validatable.Value), 93 | $"{validatable.ParamName}: {funcName}", 94 | validatable.ExceptionCustomizations, 95 | length); 96 | 97 | return ref validatable; 98 | } 99 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/StringProperties/ValidatableExtensions.StringProperties.Regex.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | using System.Text.RegularExpressions; 4 | 5 | /// 6 | /// Extension methods for string properties. 7 | /// 8 | public static partial class ValidatableExtensions 9 | { 10 | /// 11 | /// Throws an exception if the string returned from the given matches the given . 12 | /// Default is . 13 | /// 14 | /// 15 | /// The default exception thrown is an . 16 | /// 17 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 18 | public static ref readonly Validatable IfMatches( 19 | this in Validatable validatable, 20 | Func func, 21 | string regexPattern, 22 | RegexOptions regexOptions = RegexOptions.None, 23 | [CallerArgumentExpression("func")] string? funcName = null) 24 | where TValue : notnull 25 | { 26 | Validator.ThrowIfMatches( 27 | func(validatable.Value), 28 | $"{validatable.ParamName}: {funcName}", 29 | validatable.ExceptionCustomizations, 30 | regexPattern, 31 | regexOptions); 32 | 33 | return ref validatable; 34 | } 35 | 36 | /// 37 | /// Throws an exception if the string returned from the given matches the given . 38 | /// 39 | /// 40 | /// The default exception thrown is an . 41 | /// 42 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 43 | public static ref readonly Validatable IfMatches( 44 | this in Validatable validatable, 45 | Func func, 46 | Regex regex, 47 | [CallerArgumentExpression("func")] string? funcName = null) 48 | where TValue : notnull 49 | { 50 | Validator.ThrowIfMatches( 51 | func(validatable.Value), 52 | $"{validatable.ParamName}: {funcName}", 53 | validatable.ExceptionCustomizations, 54 | regex); 55 | 56 | return ref validatable; 57 | } 58 | 59 | /// 60 | /// Throws an exception if the string returned from the given does not match the given . 61 | /// Default is . 62 | /// 63 | /// 64 | /// The default exception thrown is an . 65 | /// 66 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 67 | public static ref readonly Validatable IfNotMatches( 68 | this in Validatable validatable, 69 | Func func, 70 | string regexPattern, 71 | RegexOptions regexOptions = RegexOptions.None, 72 | [CallerArgumentExpression("func")] string? funcName = null) 73 | where TValue : notnull 74 | { 75 | Validator.ThrowIfNotMatches( 76 | func(validatable.Value), 77 | $"{validatable.ParamName}: {funcName}", 78 | validatable.ExceptionCustomizations, 79 | regexPattern, 80 | regexOptions); 81 | 82 | return ref validatable; 83 | } 84 | 85 | /// 86 | /// Throws an exception if the string returned from the given does not match the given . 87 | /// 88 | /// 89 | /// The default exception thrown is an . 90 | /// 91 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 92 | public static ref readonly Validatable IfNotMatches( 93 | this in Validatable validatable, 94 | Func func, 95 | Regex regex, 96 | [CallerArgumentExpression("func")] string? funcName = null) 97 | where TValue : notnull 98 | { 99 | Validator.ThrowIfNotMatches( 100 | func(validatable.Value), 101 | $"{validatable.ParamName}: {funcName}", 102 | validatable.ExceptionCustomizations, 103 | regex); 104 | 105 | return ref validatable; 106 | } 107 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/StringProperties/ValidatableExtensions.StringProperties.Substring.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extension methods for string properties. 5 | /// 6 | public static partial class ValidatableExtensions 7 | { 8 | /// 9 | /// Throws an exception if the string returned from the given ends with . 10 | /// Default is . 11 | /// 12 | /// 13 | /// The default exception thrown is an . 14 | /// 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public static ref readonly Validatable IfEndsWith( 17 | this in Validatable validatable, 18 | Func func, 19 | string str, 20 | StringComparison comparisonType = StringComparison.Ordinal, 21 | [CallerArgumentExpression("func")] string? funcName = null) 22 | where TValue : notnull 23 | { 24 | Validator.ThrowIfEndsWith( 25 | func(validatable.Value), 26 | $"{validatable.ParamName}: {funcName}", 27 | validatable.ExceptionCustomizations, 28 | str, 29 | comparisonType); 30 | 31 | return ref validatable; 32 | } 33 | 34 | /// 35 | /// Throws an exception if the string returned from the given does not end with . 36 | /// Default is . 37 | /// 38 | /// 39 | /// The default exception thrown is an . 40 | /// 41 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 42 | public static ref readonly Validatable IfNotEndsWith( 43 | this in Validatable validatable, 44 | Func func, 45 | string str, 46 | StringComparison comparisonType = StringComparison.Ordinal, 47 | [CallerArgumentExpression("func")] string? funcName = null) 48 | where TValue : notnull 49 | { 50 | Validator.ThrowIfNotEndsWith( 51 | func(validatable.Value), 52 | $"{validatable.ParamName}: {funcName}", 53 | validatable.ExceptionCustomizations, 54 | str, 55 | comparisonType); 56 | 57 | return ref validatable; 58 | } 59 | 60 | /// 61 | /// Throws an exception if the string returned from the given starts with . 62 | /// Default is . 63 | /// 64 | /// 65 | /// The default exception thrown is an . 66 | /// 67 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 68 | public static ref readonly Validatable IfStartsWith( 69 | this in Validatable validatable, 70 | Func func, 71 | string str, 72 | StringComparison comparisonType = StringComparison.Ordinal, 73 | [CallerArgumentExpression("func")] string? funcName = null) 74 | where TValue : notnull 75 | { 76 | Validator.ThrowIfStartsWith( 77 | func(validatable.Value), 78 | $"{validatable.ParamName}: {funcName}", 79 | validatable.ExceptionCustomizations, 80 | str, 81 | comparisonType); 82 | 83 | return ref validatable; 84 | } 85 | 86 | /// 87 | /// Throws an exception if the string returned from the given does not start with . 88 | /// Default is . 89 | /// 90 | /// 91 | /// The default exception thrown is an . 92 | /// 93 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 94 | public static ref readonly Validatable IfNotStartsWith( 95 | this in Validatable validatable, 96 | Func func, 97 | string str, 98 | StringComparison comparisonType = StringComparison.Ordinal, 99 | [CallerArgumentExpression("func")] string? funcName = null) 100 | where TValue : notnull 101 | { 102 | Validator.ThrowIfNotStartsWith( 103 | func(validatable.Value), 104 | $"{validatable.ParamName}: {funcName}", 105 | validatable.ExceptionCustomizations, 106 | str, 107 | comparisonType); 108 | 109 | return ref validatable; 110 | } 111 | 112 | /// 113 | /// Throws an exception if the string returned from the given contains the given . 114 | /// Default is . 115 | /// 116 | /// 117 | /// The default exception thrown is an . 118 | /// 119 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 120 | public static ref readonly Validatable IfContains( 121 | this in Validatable validatable, 122 | Func func, 123 | string otherString, 124 | StringComparison comparisonType = StringComparison.Ordinal, 125 | [CallerArgumentExpression("func")] string? funcName = null) 126 | where TValue : notnull 127 | { 128 | Validator.ThrowIfContains( 129 | func(validatable.Value), 130 | $"{validatable.ParamName}: {funcName}", 131 | validatable.ExceptionCustomizations, 132 | otherString, 133 | comparisonType); 134 | 135 | return ref validatable; 136 | } 137 | 138 | /// 139 | /// Throws an exception if the string returned from the given does not contain the given . 140 | /// Default is . 141 | /// 142 | /// 143 | /// The default exception thrown is an . 144 | /// 145 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 146 | public static ref readonly Validatable IfNotContains( 147 | this in Validatable validatable, 148 | Func func, 149 | string otherString, 150 | StringComparison comparisonType = StringComparison.Ordinal, 151 | [CallerArgumentExpression("func")] string? funcName = null) 152 | where TValue : notnull 153 | { 154 | Validator.ThrowIfNotContains( 155 | func(validatable.Value), 156 | $"{validatable.ParamName}: {funcName}", 157 | validatable.ExceptionCustomizations, 158 | otherString, 159 | comparisonType); 160 | 161 | return ref validatable; 162 | } 163 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/Strings/ValidatableExtensions.Strings.Equality.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extension methods for strings. 5 | /// 6 | public static partial class ValidatableExtensions 7 | { 8 | /// 9 | /// Throws an exception if the string is white space only. 10 | /// 11 | /// 12 | /// The default exception thrown is an . 13 | /// 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public static ref readonly Validatable IfWhiteSpace(this in Validatable validatable) 16 | { 17 | Validator.ThrowIfWhiteSpace(validatable.Value, validatable.ParamName, validatable.ExceptionCustomizations); 18 | 19 | return ref validatable; 20 | } 21 | 22 | /// 23 | /// Throws an exception if the string is empty. 24 | /// 25 | /// 26 | /// The default exception thrown is an . 27 | /// 28 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 29 | public static ref readonly Validatable IfEmpty(this in Validatable validatable) 30 | { 31 | Validator.ThrowIfEmpty(validatable.Value, validatable.ParamName, validatable.ExceptionCustomizations); 32 | 33 | return ref validatable; 34 | } 35 | 36 | /// 37 | /// Throws an exception if the string equals the given . 38 | /// 39 | /// 40 | /// The used is . 41 | /// The default exception thrown is an . 42 | /// 43 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 44 | public static ref readonly Validatable IfEquals(this in Validatable validatable, string otherString) 45 | { 46 | Validator.ThrowIfEquals( 47 | validatable.Value, 48 | validatable.ParamName, 49 | validatable.ExceptionCustomizations, 50 | otherString, 51 | StringComparison.Ordinal); 52 | 53 | return ref validatable; 54 | } 55 | 56 | /// 57 | /// Throws an exception if the string equals the given using the given . 58 | /// 59 | /// 60 | /// The default exception thrown is an . 61 | /// 62 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 63 | public static ref readonly Validatable IfEquals( 64 | this in Validatable validatable, 65 | string otherString, 66 | StringComparison comparisonType) 67 | { 68 | Validator.ThrowIfEquals( 69 | validatable.Value, 70 | validatable.ParamName, 71 | validatable.ExceptionCustomizations, 72 | otherString, 73 | comparisonType); 74 | 75 | return ref validatable; 76 | } 77 | 78 | /// 79 | /// Throws an exception if the string does not equal the given . 80 | /// 81 | /// 82 | /// The used is . 83 | /// The default exception thrown is an . 84 | /// 85 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 86 | public static ref readonly Validatable IfNotEquals( 87 | this in Validatable validatable, 88 | string otherString) 89 | { 90 | Validator.ThrowIfNotEquals( 91 | validatable.Value, 92 | validatable.ParamName, 93 | validatable.ExceptionCustomizations, 94 | otherString, 95 | StringComparison.Ordinal); 96 | 97 | return ref validatable; 98 | } 99 | 100 | /// 101 | /// Throws an exception if the string does not equal the using the given . 102 | /// 103 | /// 104 | /// The default exception thrown is an . 105 | /// 106 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 107 | public static ref readonly Validatable IfNotEquals(this in Validatable validatable, string otherString, StringComparison comparisonType) 108 | { 109 | Validator.ThrowIfNotEquals(validatable.Value, validatable.ParamName, validatable.ExceptionCustomizations, otherString, comparisonType); 110 | 111 | return ref validatable; 112 | } 113 | 114 | /// 115 | /// Throws an exception if the string equals the given (case insensitive). 116 | /// 117 | /// 118 | /// The default exception thrown is an . 119 | /// 120 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 121 | public static ref readonly Validatable IfEqualsIgnoreCase(this in Validatable validatable, string otherString) 122 | { 123 | Validator.ThrowIfEquals( 124 | validatable.Value, 125 | validatable.ParamName, 126 | validatable.ExceptionCustomizations, 127 | otherString, 128 | StringComparison.OrdinalIgnoreCase); 129 | 130 | return ref validatable; 131 | } 132 | 133 | /// 134 | /// Throws an exception if the string does not equal the given (case insensitive). 135 | /// 136 | /// 137 | /// The used is . 138 | /// The default exception thrown is an . 139 | /// 140 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 141 | public static ref readonly Validatable IfNotEqualsIgnoreCase(this in Validatable validatable, string otherString) 142 | { 143 | Validator.ThrowIfNotEquals( 144 | validatable.Value, 145 | validatable.ParamName, 146 | validatable.ExceptionCustomizations, 147 | otherString, 148 | StringComparison.OrdinalIgnoreCase); 149 | 150 | return ref validatable; 151 | } 152 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/Strings/ValidatableExtensions.Strings.Length.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extension methods for strings. 5 | /// 6 | public static partial class ValidatableExtensions 7 | { 8 | /// 9 | /// Throws an exception if the string is longer than characters. 10 | /// 11 | /// 12 | /// The default exception thrown is an . 13 | /// 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public static ref readonly Validatable IfLongerThan(this in Validatable validatable, int length) 16 | { 17 | Validator.ThrowIfLongerThan( 18 | validatable.Value, 19 | validatable.ParamName, 20 | validatable.ExceptionCustomizations, 21 | length); 22 | 23 | return ref validatable; 24 | } 25 | 26 | /// 27 | /// Throws an exception if the string is shortter than characters. 28 | /// 29 | /// 30 | /// The default exception thrown is an . 31 | /// 32 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 33 | public static ref readonly Validatable IfShorterThan(this in Validatable validatable, int length) 34 | { 35 | Validator.ThrowIfShorterThan( 36 | validatable.Value, 37 | validatable.ParamName, 38 | validatable.ExceptionCustomizations, 39 | length); 40 | 41 | return ref validatable; 42 | } 43 | 44 | /// 45 | /// Throws an exception if the string length is equal to . 46 | /// 47 | /// 48 | /// The default exception thrown is an . 49 | /// 50 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 51 | public static ref readonly Validatable IfLengthEquals(this in Validatable validatable, int length) 52 | { 53 | Validator.ThrowIfLengthEquals( 54 | validatable.Value, 55 | validatable.ParamName, 56 | validatable.ExceptionCustomizations, 57 | length); 58 | 59 | return ref validatable; 60 | } 61 | 62 | /// 63 | /// Throws an exception if the string length is not equal to . 64 | /// 65 | /// 66 | /// The default exception thrown is an . 67 | /// 68 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 69 | public static ref readonly Validatable IfLengthNotEquals( 70 | this in Validatable validatable, 71 | int length) 72 | { 73 | Validator.ThrowIfLengthNotEquals( 74 | validatable.Value, 75 | validatable.ParamName, 76 | validatable.ExceptionCustomizations, 77 | length); 78 | 79 | return ref validatable; 80 | } 81 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/Strings/ValidatableExtensions.Strings.Regex.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | using System.Text.RegularExpressions; 4 | 5 | /// 6 | /// Extension methods for strings. 7 | /// 8 | public static partial class ValidatableExtensions 9 | { 10 | /// 11 | /// Throws an exception if the string matches the given . 12 | /// Default is . 13 | /// 14 | /// 15 | /// The default exception thrown is an . 16 | /// 17 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 18 | public static ref readonly Validatable IfMatches( 19 | this in Validatable validatable, 20 | string regexPattern, 21 | RegexOptions regexOptions = RegexOptions.None) 22 | { 23 | Validator.ThrowIfMatches( 24 | validatable.Value, 25 | validatable.ParamName, 26 | validatable.ExceptionCustomizations, 27 | regexPattern, 28 | regexOptions); 29 | 30 | return ref validatable; 31 | } 32 | 33 | /// 34 | /// Throws an exception if the string matches the given . 35 | /// 36 | /// 37 | /// The default exception thrown is an . 38 | /// 39 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 40 | public static ref readonly Validatable IfMatches(this in Validatable validatable, Regex regex) 41 | { 42 | Validator.ThrowIfMatches(validatable.Value, validatable.ParamName, validatable.ExceptionCustomizations, regex); 43 | 44 | return ref validatable; 45 | } 46 | 47 | /// 48 | /// Throws an exception if the string does not match the given . 49 | /// Default is . 50 | /// 51 | /// 52 | /// The default exception thrown is an . 53 | /// 54 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 55 | public static ref readonly Validatable IfNotMatches( 56 | this in Validatable validatable, 57 | string regexPattern, 58 | RegexOptions regexOptions = RegexOptions.None) 59 | { 60 | Validator.ThrowIfNotMatches( 61 | validatable.Value, 62 | validatable.ParamName, 63 | validatable.ExceptionCustomizations, 64 | regexPattern, 65 | regexOptions); 66 | 67 | return ref validatable; 68 | } 69 | 70 | /// 71 | /// Throws an exception if the string does not match the given . 72 | /// 73 | /// 74 | /// The default exception thrown is an . 75 | /// 76 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 77 | public static ref readonly Validatable IfNotMatches(this in Validatable validatable, Regex regex) 78 | { 79 | Validator.ThrowIfNotMatches( 80 | validatable.Value, 81 | validatable.ParamName, 82 | validatable.ExceptionCustomizations, 83 | regex); 84 | 85 | return ref validatable; 86 | } 87 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/Strings/ValidatableExtensions.Strings.Substring.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extension methods for strings. 5 | /// 6 | public static partial class ValidatableExtensions 7 | { 8 | /// 9 | /// Throws an exception if the string ends with . 10 | /// Default is . 11 | /// 12 | /// 13 | /// The default exception thrown is an . 14 | /// 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public static ref readonly Validatable IfEndsWith( 17 | this in Validatable validatable, 18 | string str, 19 | StringComparison comparisonType = StringComparison.Ordinal) 20 | { 21 | Validator.ThrowIfEndsWith( 22 | validatable.Value, 23 | validatable.ParamName, 24 | validatable.ExceptionCustomizations, 25 | str, 26 | comparisonType); 27 | 28 | return ref validatable; 29 | } 30 | 31 | /// 32 | /// Throws an exception if the string does not end with . 33 | /// Default is . 34 | /// 35 | /// 36 | /// The default exception thrown is an . 37 | /// 38 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 39 | public static ref readonly Validatable IfNotEndsWith( 40 | this in Validatable validatable, 41 | string str, 42 | StringComparison comparisonType = StringComparison.Ordinal) 43 | { 44 | Validator.ThrowIfNotEndsWith( 45 | validatable.Value, 46 | validatable.ParamName, 47 | validatable.ExceptionCustomizations, 48 | str, 49 | comparisonType); 50 | 51 | return ref validatable; 52 | } 53 | 54 | /// 55 | /// Throws an exception if the string starts with . 56 | /// Default is . 57 | /// 58 | /// 59 | /// The default exception thrown is an . 60 | /// 61 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 62 | public static ref readonly Validatable IfStartsWith( 63 | this in Validatable validatable, 64 | string str, 65 | StringComparison comparisonType = StringComparison.Ordinal) 66 | { 67 | Validator.ThrowIfStartsWith( 68 | validatable.Value, 69 | validatable.ParamName, 70 | validatable.ExceptionCustomizations, 71 | str, 72 | comparisonType); 73 | 74 | return ref validatable; 75 | } 76 | 77 | /// 78 | /// Throws an exception if the string does not start with . 79 | /// Default is . 80 | /// 81 | /// 82 | /// The default exception thrown is an . 83 | /// 84 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 85 | public static ref readonly Validatable IfNotStartsWith( 86 | this in Validatable validatable, 87 | string str, 88 | StringComparison comparisonType = StringComparison.Ordinal) 89 | { 90 | Validator.ThrowIfNotStartsWith( 91 | validatable.Value, 92 | validatable.ParamName, 93 | validatable.ExceptionCustomizations, 94 | str, 95 | comparisonType); 96 | 97 | return ref validatable; 98 | } 99 | 100 | /// 101 | /// Throws an exception if the string contains the given . 102 | /// Default is . 103 | /// 104 | /// 105 | /// The default exception thrown is an . 106 | /// 107 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 108 | public static ref readonly Validatable IfContains( 109 | this in Validatable validatable, 110 | string otherString, 111 | StringComparison comparisonType = StringComparison.Ordinal) 112 | { 113 | Validator.ThrowIfContains( 114 | validatable.Value, 115 | validatable.ParamName, 116 | validatable.ExceptionCustomizations, 117 | otherString, 118 | comparisonType); 119 | 120 | return ref validatable; 121 | } 122 | 123 | /// 124 | /// Throws an exception if the string does not contain the given . 125 | /// Default is . 126 | /// 127 | /// 128 | /// The default exception thrown is an . 129 | /// 130 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 131 | public static ref readonly Validatable IfNotContains( 132 | this in Validatable validatable, 133 | string otherString, 134 | StringComparison comparisonType = StringComparison.Ordinal) 135 | { 136 | Validator.ThrowIfNotContains( 137 | validatable.Value, 138 | validatable.ParamName, 139 | validatable.ExceptionCustomizations, 140 | otherString, 141 | comparisonType); 142 | 143 | return ref validatable; 144 | } 145 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/ValidatableExtensions.BooleanProperties.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extension methods for boolean properties. 5 | /// 6 | public static partial class ValidatableExtensions 7 | { 8 | /// 9 | /// Throws an exception if the boolean value returned from the given is true. 10 | /// 11 | /// 12 | /// The default exception thrown is an . 13 | /// 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public static ref readonly Validatable IfTrue( 16 | this in Validatable validatable, 17 | Func func, 18 | [CallerArgumentExpression("func")] string? funcName = null) 19 | where TValue : notnull 20 | { 21 | if (func(validatable.Value)) 22 | { 23 | ExceptionThrower.Throw( 24 | validatable.ParamName, 25 | validatable.ExceptionCustomizations, 26 | $"Value should not meet condition (condition: '{funcName}')."); 27 | } 28 | 29 | return ref validatable; 30 | } 31 | 32 | /// 33 | /// Throws an exception if the boolean value returned from the given is false. 34 | /// 35 | /// 36 | /// The default exception thrown is an . 37 | /// 38 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 39 | public static ref readonly Validatable IfFalse( 40 | this in Validatable validatable, 41 | Func func, 42 | [CallerArgumentExpression("func")] string? funcName = null) 43 | where TValue : notnull 44 | { 45 | if (!func(validatable.Value)) 46 | { 47 | ExceptionThrower.Throw( 48 | validatable.ParamName, 49 | validatable.ExceptionCustomizations, 50 | $"Value should meet condition (condition: '{funcName}')."); 51 | } 52 | 53 | return ref validatable; 54 | } 55 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/ValidatableExtensions.Booleans.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extension methods for booleans. 5 | /// 6 | public static partial class ValidatableExtensions 7 | { 8 | /// 9 | /// Throws an exception if the boolean value is true. 10 | /// 11 | /// 12 | /// The default exception thrown is an . 13 | /// 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public static ref readonly Validatable IfTrue(this in Validatable validatable) 16 | { 17 | if (validatable.Value) 18 | { 19 | ExceptionThrower.Throw( 20 | validatable.ParamName, 21 | validatable.ExceptionCustomizations, 22 | "Value should not be true."); 23 | } 24 | 25 | return ref validatable; 26 | } 27 | 28 | /// 29 | /// Throws an exception if the boolean value is false. 30 | /// 31 | /// 32 | /// The default exception thrown is an . 33 | /// 34 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 35 | public static ref readonly Validatable IfFalse(this in Validatable validatable) 36 | { 37 | if (!validatable.Value) 38 | { 39 | ExceptionThrower.Throw( 40 | validatable.ParamName, 41 | validatable.ExceptionCustomizations, 42 | "Value should be true."); 43 | } 44 | 45 | return ref validatable; 46 | } 47 | 48 | /// 49 | /// Throws an exception if the is true. 50 | /// 51 | /// 52 | /// The default exception thrown is an . 53 | /// 54 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 55 | public static ref readonly Validatable IfTrue( 56 | this in Validatable validatable, 57 | bool condition, 58 | [CallerArgumentExpression("condition")] string? conditionParamName = null) 59 | where TValue : notnull 60 | { 61 | if (condition) 62 | { 63 | ExceptionThrower.Throw( 64 | validatable.ParamName, 65 | validatable.ExceptionCustomizations, 66 | $"Value should not meet condition (condition: '{conditionParamName}')."); 67 | } 68 | 69 | return ref validatable; 70 | } 71 | 72 | /// 73 | /// Throws an exception if the is false. 74 | /// 75 | /// 76 | /// The default exception thrown is an . 77 | /// 78 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 79 | public static ref readonly Validatable IfFalse( 80 | this in Validatable validatable, 81 | bool condition, 82 | [CallerArgumentExpression("condition")] string? conditionParamName = null) 83 | where TValue : notnull 84 | { 85 | if (!condition) 86 | { 87 | ExceptionThrower.Throw( 88 | validatable.ParamName, 89 | validatable.ExceptionCustomizations, 90 | $"Value should meet condition (condition: '{conditionParamName}')."); 91 | } 92 | 93 | return ref validatable; 94 | } 95 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/ValidatableExtensions.Collections.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extension methods for collections. 5 | /// 6 | public static partial class ValidatableExtensions 7 | { 8 | /// 9 | /// Throws an exception if the collection is empty. 10 | /// Important note: if the collection is a non-evaluated expression, the expression will be evaluated. 11 | /// 12 | /// 13 | /// The default exception thrown is an . 14 | /// 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public static ref readonly Validatable IfEmpty(this in Validatable validatable) 17 | where TValue : notnull, IEnumerable 18 | { 19 | Validator.ThrowIfCount( 20 | validatable.Value, 21 | 0, 22 | validatable.ParamName, 23 | validatable.ExceptionCustomizations, 24 | "Collection should not be empty."); 25 | 26 | return ref validatable; 27 | } 28 | 29 | /// 30 | /// Throws an exception if the collection is not empty. 31 | /// Important note: if the collection is a non-evaluated expression, the expression will be evaluated. 32 | /// 33 | /// 34 | /// The default exception thrown is an . 35 | /// 36 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 37 | public static ref readonly Validatable IfNotEmpty(this in Validatable validatable) 38 | where TValue : notnull, IEnumerable 39 | { 40 | Validator.ThrowIfCountNot( 41 | validatable.Value, 42 | 0, 43 | validatable.ParamName, 44 | validatable.ExceptionCustomizations, 45 | "Collection should be empty."); 46 | 47 | return ref validatable; 48 | } 49 | 50 | /// 51 | /// Throws an exception if the collection count does not match the specified . 52 | /// Important note: if the collection is a non-evaluated expression, the expression will be evaluated. 53 | /// 54 | /// 55 | /// The default exception thrown is an . 56 | /// 57 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 58 | public static ref readonly Validatable IfCountNotEquals( 59 | this in Validatable validatable, 60 | int count) 61 | where TValue : notnull, IEnumerable 62 | { 63 | Validator.ThrowIfCountNot(validatable.Value, count, validatable.ParamName, validatable.ExceptionCustomizations); 64 | 65 | return ref validatable; 66 | } 67 | 68 | /// 69 | /// Throws an exception if the collection count matches the specified . 70 | /// Important note: if the collection is a non-evaluated expression, the expression will be evaluated. 71 | /// 72 | /// 73 | /// The default exception thrown is an . 74 | /// 75 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 76 | public static ref readonly Validatable IfCountEquals( 77 | this in Validatable validatable, 78 | int count) 79 | where TValue : notnull, IEnumerable 80 | { 81 | Validator.ThrowIfCount(validatable.Value, count, validatable.ParamName, validatable.ExceptionCustomizations); 82 | 83 | return ref validatable; 84 | } 85 | 86 | /// 87 | /// Throws an exception if the collection count is greater than the specified . 88 | /// Important note: if the collection is a non-evaluated expression, the expression will be evaluated. 89 | /// 90 | /// 91 | /// The default exception thrown is an . 92 | /// 93 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 94 | public static ref readonly Validatable IfCountGreaterThan( 95 | this in Validatable validatable, 96 | int count) 97 | where TValue : notnull, IEnumerable 98 | { 99 | Validator.ThrowIfCountGreaterThan( 100 | validatable.Value, 101 | count, 102 | validatable.ParamName, 103 | validatable.ExceptionCustomizations); 104 | 105 | return ref validatable; 106 | } 107 | 108 | /// 109 | /// Throws an exception if the collection count is less than the specified . 110 | /// Important note: if the collection is a non-evaluated expression, the expression will be evaluated. 111 | /// 112 | /// 113 | /// The default exception thrown is an . 114 | /// 115 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 116 | public static ref readonly Validatable IfCountLessThan( 117 | this in Validatable validatable, 118 | int count) 119 | where TValue : notnull, IEnumerable 120 | { 121 | Validator.ThrowIfCountLessThan( 122 | validatable.Value, 123 | count, 124 | validatable.ParamName, 125 | validatable.ExceptionCustomizations); 126 | 127 | return ref validatable; 128 | } 129 | 130 | /// 131 | /// Throws an exception if the collection contains null elements. 132 | /// Important note: if the collection is a non-evaluated expression, the expression will be evaluated. 133 | /// 134 | /// 135 | /// The default exception thrown is an . 136 | /// 137 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 138 | public static ref readonly Validatable IfHasNullElements(this in Validatable validatable) 139 | where TValue : notnull, IEnumerable 140 | { 141 | Validator.ThrowIfHasNullElements(validatable.Value, validatable.ParamName, validatable.ExceptionCustomizations); 142 | 143 | return ref validatable; 144 | } 145 | 146 | /// 147 | /// Throws an exception if the collection contains the given . 148 | /// Important note: if the collection is a non-evaluated expression, the expression will be evaluated. 149 | /// 150 | /// 151 | /// The default exception thrown is an . 152 | /// 153 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 154 | public static ref readonly Validatable IfContains( 155 | this in Validatable validatable, 156 | TElement element) 157 | where TValue : notnull, IEnumerable 158 | where TElement : notnull 159 | { 160 | Validator.ThrowIfContainsElement( 161 | validatable.Value, 162 | element, 163 | validatable.ParamName, 164 | validatable.ExceptionCustomizations); 165 | 166 | return ref validatable; 167 | } 168 | 169 | /// 170 | /// Throws an exception if the collection does not contain the given . 171 | /// Important note: if the collection is a non-evaluated expression, the expression will be evaluated. 172 | /// 173 | /// 174 | /// The default exception thrown is an . 175 | /// 176 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 177 | public static ref readonly Validatable IfNotContains( 178 | this in Validatable validatable, 179 | TElement element) 180 | where TValue : notnull, IEnumerable 181 | where TElement : notnull 182 | { 183 | Validator.ThrowIfNotContainsElement( 184 | validatable.Value, 185 | element, 186 | validatable.ParamName, 187 | validatable.ExceptionCustomizations); 188 | 189 | return ref validatable; 190 | } 191 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/ValidatableExtensions.Comparables.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extension methods for comparables (int, double, decimal, long, float, short, DateTime, DateOnly, TimeOnly etc.). 5 | /// 6 | public static partial class ValidatableExtensions 7 | { 8 | /// 9 | /// Throws an exception if the value is greater than . 10 | /// 11 | /// 12 | /// The default exception thrown is an . 13 | /// 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public static ref readonly Validatable IfGreaterThan( 16 | this in Validatable validatable, 17 | TValue n) 18 | where TValue : notnull, IComparable 19 | { 20 | Validator.ThrowIfGreaterThan(validatable.Value, n, validatable.ParamName, validatable.ExceptionCustomizations); 21 | 22 | return ref validatable; 23 | } 24 | 25 | /// 26 | /// Throws an exception if the value is greater than or equal to . 27 | /// 28 | /// 29 | /// The default exception thrown is an . 30 | /// 31 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 32 | public static ref readonly Validatable IfGreaterThanOrEqualTo( 33 | this in Validatable validatable, 34 | TValue n) 35 | where TValue : notnull, IComparable 36 | { 37 | Validator.ThrowIfGreaterThanOrEqualTo(validatable.Value, n, validatable.ParamName, validatable.ExceptionCustomizations); 38 | 39 | return ref validatable; 40 | } 41 | 42 | /// 43 | /// Throws an exception if the value is less than . 44 | /// 45 | /// 46 | /// The default exception thrown is an . 47 | /// 48 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 49 | public static ref readonly Validatable IfLessThan(this in Validatable validatable, TValue n) 50 | where TValue : notnull, IComparable 51 | { 52 | Validator.ThrowIfLessThan(validatable.Value, n, validatable.ParamName, validatable.ExceptionCustomizations); 53 | 54 | return ref validatable; 55 | } 56 | 57 | /// 58 | /// Throws an exception if the value is less than or equal to . 59 | /// 60 | /// 61 | /// The default exception thrown is an . 62 | /// 63 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 64 | public static ref readonly Validatable IfLessThanOrEqualTo(this in Validatable validatable, TValue n) 65 | where TValue : notnull, IComparable 66 | { 67 | Validator.ThrowIfLessThanOrEqualTo(validatable.Value, n, validatable.ParamName, validatable.ExceptionCustomizations); 68 | 69 | return ref validatable; 70 | } 71 | 72 | /// 73 | /// Throws an exception if the value is greater than 0. 74 | /// 75 | /// 76 | /// The default exception thrown is an . 77 | /// 78 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 79 | public static ref readonly Validatable IfPositive(this in Validatable validatable) 80 | where TValue : notnull, IComparable 81 | { 82 | Validator.ThrowIfGreaterThan( 83 | validatable.Value, 84 | default!, 85 | validatable.ParamName, 86 | validatable.ExceptionCustomizations); 87 | 88 | return ref validatable; 89 | } 90 | 91 | /// 92 | /// Throws an exception if the value is greater than or equal to 0. 93 | /// 94 | /// 95 | /// The default exception thrown is an . 96 | /// 97 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 98 | public static ref readonly Validatable IfPositiveOrZero(this in Validatable validatable) 99 | where TValue : notnull, IComparable 100 | { 101 | Validator.ThrowIfGreaterThanOrEqualTo( 102 | validatable.Value, 103 | default!, 104 | validatable.ParamName, 105 | validatable.ExceptionCustomizations); 106 | 107 | return ref validatable; 108 | } 109 | 110 | /// 111 | /// Throws an exception if the value is less than 0. 112 | /// 113 | /// 114 | /// The default exception thrown is an . 115 | /// 116 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 117 | public static ref readonly Validatable IfNegative(this in Validatable validatable) 118 | where TValue : notnull, IComparable 119 | { 120 | Validator.ThrowIfLessThan( 121 | validatable.Value, 122 | default!, 123 | validatable.ParamName, 124 | validatable.ExceptionCustomizations); 125 | 126 | return ref validatable; 127 | } 128 | 129 | /// 130 | /// Throws an exception if the value is less than or equal to 0. 131 | /// 132 | /// 133 | /// The default exception thrown is an . 134 | /// 135 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 136 | public static ref readonly Validatable IfNegativeOrZero(this in Validatable validatable) 137 | where TValue : notnull, IComparable 138 | { 139 | Validator.ThrowIfLessThanOrEqualTo( 140 | validatable.Value, 141 | default!, 142 | validatable.ParamName, 143 | validatable.ExceptionCustomizations); 144 | 145 | return ref validatable; 146 | } 147 | 148 | /// 149 | /// Throws an exception if the value is not between and . 150 | /// 151 | /// The validatable being validated. 152 | /// The minimum value, inclusive (equals or greater than). 153 | /// The maximum value, inclusive (equals or less than). 154 | /// 155 | /// The default exception thrown is an . 156 | /// 157 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 158 | public static ref readonly Validatable IfOutOfRange( 159 | this in Validatable validatable, 160 | TValue min, 161 | TValue max) 162 | where TValue : notnull, IComparable 163 | { 164 | Validator.ThrowIfNotInRange( 165 | validatable.Value, 166 | min, 167 | max, 168 | validatable.ParamName, 169 | validatable.ExceptionCustomizations); 170 | 171 | return ref validatable; 172 | } 173 | 174 | /// 175 | /// Throws an exception if the value is between and . 176 | /// 177 | /// The validatable being validated. 178 | /// The minimum value, inclusive (equals or greater than). 179 | /// The maximum value, inclusive (equals or less than). 180 | /// 181 | /// The default exception thrown is an . 182 | /// 183 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 184 | public static ref readonly Validatable IfInRange( 185 | this in Validatable validatable, 186 | TValue min, 187 | TValue max) 188 | where TValue : notnull, IComparable 189 | { 190 | Validator.ThrowIfInRange( 191 | validatable.Value, 192 | min, 193 | max, 194 | validatable.ParamName, 195 | validatable.ExceptionCustomizations); 196 | 197 | return ref validatable; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/ValidatableExtensions/ValidatableExtensions.ConditionalCompilation.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | using System.Diagnostics; 4 | 5 | /// 6 | /// Extension methods for controlling whether the "throw" rule will be ignored by the compiler. 7 | /// 8 | public static partial class ValidatableExtensions 9 | { 10 | /// 11 | /// Removes the entire "throw" rule when the build is not debug. 12 | /// 13 | [Conditional("DEBUG")] 14 | public static void OnlyInDebug(this in Validatable validatable) 15 | where TValue : notnull 16 | { 17 | } 18 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/ValidatableExtensions.DateTimeProperties.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extension methods for properties. 5 | /// 6 | public static partial class ValidatableExtensions 7 | { 8 | /// 9 | /// Throws an exception if the of the returned 10 | /// from the given is . 11 | /// 12 | /// 13 | /// The default exception thrown is an . 14 | /// 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public static ref readonly Validatable IfUtc( 17 | this in Validatable validatable, 18 | Func func, 19 | [CallerArgumentExpression("func")] string? funcName = null) 20 | where TValue : notnull 21 | { 22 | Validator.ThrowIfKind( 23 | func(validatable.Value), 24 | DateTimeKind.Utc, 25 | $"{validatable.ParamName}: {funcName}", 26 | validatable.ExceptionCustomizations); 27 | 28 | return ref validatable; 29 | } 30 | 31 | /// 32 | /// Throws an exception if the of the returned 33 | /// from the given is not . 34 | /// 35 | /// 36 | /// The default exception thrown is an . 37 | /// 38 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 39 | public static ref readonly Validatable IfNotUtc( 40 | this in Validatable validatable, 41 | Func func, 42 | [CallerArgumentExpression("func")] string? funcName = null) 43 | where TValue : notnull 44 | { 45 | Validator.ThrowIfNotKind( 46 | func(validatable.Value), 47 | DateTimeKind.Utc, 48 | $"{validatable.ParamName}: {funcName}", 49 | validatable.ExceptionCustomizations); 50 | 51 | return ref validatable; 52 | } 53 | 54 | /// 55 | /// Throws an exception if the of the returned 56 | /// from the given matches the given . 57 | /// 58 | /// 59 | /// The default exception thrown is an . 60 | /// 61 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 62 | public static ref readonly Validatable IfDateTimeKind( 63 | this in Validatable validatable, 64 | Func func, 65 | DateTimeKind kind, 66 | [CallerArgumentExpression("func")] string? funcName = null) 67 | where TValue : notnull 68 | { 69 | Validator.ThrowIfKind( 70 | func(validatable.Value), 71 | kind, 72 | $"{validatable.ParamName}: {funcName}", 73 | validatable.ExceptionCustomizations); 74 | 75 | return ref validatable; 76 | } 77 | 78 | /// 79 | /// Throws an exception if the of the returned 80 | /// from the given does not match the given . 81 | /// 82 | /// 83 | /// The default exception thrown is an . 84 | /// 85 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 86 | public static ref readonly Validatable IfDateTimeKindNot( 87 | this in Validatable validatable, 88 | Func func, 89 | DateTimeKind kind, 90 | [CallerArgumentExpression("func")] string? funcName = null) 91 | where TValue : notnull 92 | { 93 | Validator.ThrowIfNotKind( 94 | func(validatable.Value), 95 | kind, 96 | $"{validatable.ParamName}: {funcName}", 97 | validatable.ExceptionCustomizations); 98 | 99 | return ref validatable; 100 | } 101 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/ValidatableExtensions.DateTimes.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extension methods for s. 5 | /// 6 | public static partial class ValidatableExtensions 7 | { 8 | /// 9 | /// Throws an exception if the is . 10 | /// 11 | /// 12 | /// The default exception thrown is an . 13 | /// 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public static ref readonly Validatable IfUtc(this in Validatable validatable) 16 | { 17 | Validator.ThrowIfKind( 18 | validatable.Value, 19 | DateTimeKind.Utc, 20 | validatable.ParamName, 21 | validatable.ExceptionCustomizations); 22 | 23 | return ref validatable; 24 | } 25 | 26 | /// 27 | /// Throws an exception if the is not . 28 | /// 29 | /// 30 | /// The default exception thrown is an . 31 | /// 32 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 33 | public static ref readonly Validatable IfNotUtc(this in Validatable validatable) 34 | { 35 | Validator.ThrowIfNotKind( 36 | validatable.Value, 37 | DateTimeKind.Utc, 38 | validatable.ParamName, 39 | validatable.ExceptionCustomizations); 40 | 41 | return ref validatable; 42 | } 43 | 44 | /// 45 | /// Throws an exception if the matches the given . 46 | /// 47 | /// 48 | /// The default exception thrown is an . 49 | /// 50 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 51 | public static ref readonly Validatable IfDateTimeKind( 52 | this in Validatable validatable, 53 | DateTimeKind kind) 54 | { 55 | Validator.ThrowIfKind(validatable.Value, kind, validatable.ParamName, validatable.ExceptionCustomizations); 56 | 57 | return ref validatable; 58 | } 59 | 60 | /// 61 | /// Throws an exception if the does not match the given . 62 | /// 63 | /// 64 | /// The default exception thrown is an . 65 | /// 66 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 67 | public static ref readonly Validatable IfDateTimeKindNot( 68 | this in Validatable validatable, 69 | DateTimeKind kind) 70 | { 71 | Validator.ThrowIfNotKind(validatable.Value, kind, validatable.ParamName, validatable.ExceptionCustomizations); 72 | 73 | return ref validatable; 74 | } 75 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/ValidatableExtensions.EnumProperties.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extension methods for enum properties. 5 | /// 6 | public static partial class ValidatableExtensions 7 | { 8 | /// 9 | /// Throws an exception if the enum value returned from the given 10 | /// is not defined in the enum. 11 | /// 12 | /// 13 | /// The default exception thrown is an . 14 | /// 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public static ref readonly Validatable IfOutOfRange( 17 | this in Validatable validatable, 18 | Func func, 19 | [CallerArgumentExpression("func")] string? funcName = null) 20 | where TValue : notnull 21 | where TEnumValue : struct, Enum 22 | { 23 | Validator.ThrowIfOutOfRange( 24 | func(validatable.Value), 25 | $"{validatable.ParamName}: {funcName}", 26 | validatable.ExceptionCustomizations); 27 | 28 | return ref validatable; 29 | } 30 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/ValidatableExtensions.Enums.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extension methods for enums. 5 | /// 6 | public static partial class ValidatableExtensions 7 | { 8 | /// 9 | /// Throws an exception if the enum value is not defined in the enum. 10 | /// 11 | /// 12 | /// The default exception thrown is an . 13 | /// 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public static ref readonly Validatable IfOutOfRange(this in Validatable validatable) 16 | where TValue : struct, Enum 17 | { 18 | Validator.ThrowIfOutOfRange(validatable.Value, validatable.ParamName, validatable.ExceptionCustomizations); 19 | 20 | return ref validatable; 21 | } 22 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/ValidatableExtensions.Equalities.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extension methods for equalities. 5 | /// 6 | public static partial class ValidatableExtensions 7 | { 8 | /// 9 | /// Throws an exception if the value is equal to the default value of type . 10 | /// 11 | /// 12 | /// The default exception thrown is an . 13 | /// 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public static ref readonly Validatable IfDefault(this in Validatable validatable) 16 | where TValue : struct 17 | { 18 | Validator.ThrowIfEquals( 19 | validatable.Value, 20 | default, 21 | validatable.ParamName, 22 | validatable.ExceptionCustomizations, 23 | "Value should not be default."); 24 | 25 | return ref validatable; 26 | } 27 | 28 | /// 29 | /// Throws an exception if the value is not equal to the default value of type . 30 | /// 31 | /// 32 | /// The default exception thrown is an . 33 | /// 34 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 35 | public static ref readonly Validatable IfNotDefault(this in Validatable validatable) 36 | where TValue : struct 37 | { 38 | Validator.ThrowIfNotEquals( 39 | validatable.Value, 40 | default, 41 | validatable.ParamName, 42 | validatable.ExceptionCustomizations, 43 | "Value should be default."); 44 | 45 | return ref validatable; 46 | } 47 | 48 | /// 49 | /// Throws an exception if the value equals . 50 | /// 51 | /// 52 | /// The default exception thrown is an . 53 | /// 54 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 55 | public static ref readonly Validatable IfEquals(this in Validatable validatable, TValue other) 56 | where TValue : notnull 57 | { 58 | Validator.ThrowIfEquals(validatable.Value, other, validatable.ParamName, validatable.ExceptionCustomizations); 59 | 60 | return ref validatable; 61 | } 62 | 63 | /// 64 | /// Throws an exception if the value does not equal . 65 | /// 66 | /// 67 | /// The default exception thrown is an . 68 | /// 69 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 70 | public static ref readonly Validatable IfNotEquals( 71 | this in Validatable validatable, 72 | TValue other) 73 | where TValue : notnull 74 | { 75 | Validator.ThrowIfNotEquals(validatable.Value, other, validatable.ParamName, validatable.ExceptionCustomizations); 76 | 77 | return ref validatable; 78 | } 79 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/ValidatableExtensions.EqualityProperties.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extension methods for property equalities. 5 | /// 6 | public static partial class ValidatableExtensions 7 | { 8 | /// 9 | /// Throws an exception if the value returned from the given is equal to null. 10 | /// 11 | /// 12 | /// The default exception thrown is an . 13 | /// 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public static ref readonly Validatable IfNull( 16 | this in Validatable validatable, 17 | Func func, 18 | [CallerArgumentExpression("func")] string? funcName = null) 19 | where TValue : notnull 20 | { 21 | if (func(validatable.Value) is null) 22 | { 23 | ExceptionThrower.ThrowNull($"{validatable.ParamName}: {funcName}", validatable.ExceptionCustomizations); 24 | } 25 | 26 | return ref validatable; 27 | } 28 | 29 | /// 30 | /// Throws an exception if the value returned from the given is not equal to null. 31 | /// 32 | /// 33 | /// The default exception thrown is an . 34 | /// 35 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 36 | public static ref readonly Validatable IfNotNull( 37 | this in Validatable validatable, 38 | Func func, 39 | [CallerArgumentExpression("func")] string? funcName = null) 40 | where TValue : notnull 41 | { 42 | if (func(validatable.Value) is not null) 43 | { 44 | ExceptionThrower.Throw($"{validatable.ParamName}: {funcName}", validatable.ExceptionCustomizations, "Value should be null."); 45 | } 46 | 47 | return ref validatable; 48 | } 49 | 50 | /// 51 | /// Throws an exception if the value returned from the given is equal to the default value of type . 52 | /// 53 | /// 54 | /// The default exception thrown is an . 55 | /// 56 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 57 | public static ref readonly Validatable IfDefault( 58 | this in Validatable validatable, 59 | Func func, 60 | [CallerArgumentExpression("func")] string? funcName = null) 61 | where TValue : notnull 62 | where TResult : struct 63 | { 64 | Validator.ThrowIfEquals( 65 | func(validatable.Value), 66 | default, 67 | $"{validatable.ParamName}: {funcName}", 68 | validatable.ExceptionCustomizations, 69 | "Value should not be default."); 70 | 71 | return ref validatable; 72 | } 73 | 74 | /// 75 | /// Throws an exception if the value returned from the given is not equal to the default value of type . 76 | /// 77 | /// 78 | /// The default exception thrown is an . 79 | /// 80 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 81 | public static ref readonly Validatable IfNotDefault( 82 | this in Validatable validatable, 83 | Func func, 84 | [CallerArgumentExpression("func")] string? funcName = null) 85 | where TValue : notnull 86 | where TResult : struct 87 | { 88 | Validator.ThrowIfNotEquals( 89 | func(validatable.Value), 90 | default, 91 | $"{validatable.ParamName}: {funcName}", 92 | validatable.ExceptionCustomizations, 93 | "Value should be default."); 94 | 95 | return ref validatable; 96 | } 97 | 98 | /// 99 | /// Throws an exception if the value returned from the given is equal to . 100 | /// 101 | /// 102 | /// The default exception thrown is an . 103 | /// 104 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 105 | public static ref readonly Validatable IfEquals( 106 | this in Validatable validatable, 107 | Func func, 108 | TResult other, 109 | [CallerArgumentExpression("func")] string? funcName = null) 110 | where TValue : notnull 111 | where TResult : notnull 112 | { 113 | Validator.ThrowIfEquals( 114 | value: func(validatable.Value), 115 | other: other, 116 | paramName: $"{validatable.ParamName}: {funcName}", 117 | exceptionCustomizations: validatable.ExceptionCustomizations); 118 | 119 | return ref validatable; 120 | } 121 | 122 | /// 123 | /// Throws an exception if the value returned from the given is not equal to . 124 | /// 125 | /// 126 | /// The default exception thrown is an . 127 | /// 128 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 129 | public static ref readonly Validatable IfNotEquals( 130 | this in Validatable validatable, 131 | Func func, 132 | TResult other, 133 | [CallerArgumentExpression("func")] string? funcName = null) 134 | where TValue : notnull 135 | where TResult : notnull 136 | { 137 | Validator.ThrowIfNotEquals( 138 | value: func(validatable.Value), 139 | other: other, 140 | paramName: $"{validatable.ParamName}: {funcName}", 141 | exceptionCustomizations: validatable.ExceptionCustomizations); 142 | 143 | return ref validatable; 144 | } 145 | } -------------------------------------------------------------------------------- /src/ValidatableExtensions/ValidatalbeExtensions.Uris.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Extension methods s. 5 | /// 6 | public static partial class ValidatableExtensions 7 | { 8 | /// 9 | /// Throws an exception if scheme of the is . 10 | /// 11 | /// 12 | /// The default exception thrown is an . 13 | /// 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public static ref readonly Validatable IfHttp(this in Validatable validatable) 16 | { 17 | Validator.ThrowIfScheme(validatable.Value, Uri.UriSchemeHttp, validatable.ParamName, validatable.ExceptionCustomizations); 18 | 19 | return ref validatable; 20 | } 21 | 22 | /// 23 | /// Throws an exception if scheme of the is not . 24 | /// 25 | /// 26 | /// The default exception thrown is an . 27 | /// 28 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 29 | public static ref readonly Validatable IfNotHttp(this in Validatable validatable) 30 | { 31 | Validator.ThrowIfSchemeNot(validatable.Value, Uri.UriSchemeHttp, validatable.ParamName, validatable.ExceptionCustomizations); 32 | 33 | return ref validatable; 34 | } 35 | 36 | /// 37 | /// Throws an exception if scheme of the is . 38 | /// 39 | /// 40 | /// The default exception thrown is an . 41 | /// 42 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 43 | public static ref readonly Validatable IfHttps(this in Validatable validatable) 44 | { 45 | Validator.ThrowIfScheme(validatable.Value, Uri.UriSchemeHttps, validatable.ParamName, validatable.ExceptionCustomizations); 46 | 47 | return ref validatable; 48 | } 49 | 50 | /// 51 | /// Throws an exception if scheme of the is not . 52 | /// 53 | /// 54 | /// The default exception thrown is an . 55 | /// 56 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 57 | public static ref readonly Validatable IfNotHttps(this in Validatable validatable) 58 | { 59 | Validator.ThrowIfSchemeNot(validatable.Value, Uri.UriSchemeHttps, validatable.ParamName, validatable.ExceptionCustomizations); 60 | 61 | return ref validatable; 62 | } 63 | 64 | /// 65 | /// Throws an exception if scheme of the matches the given . 66 | /// 67 | /// 68 | /// The default exception thrown is an . 69 | /// 70 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 71 | public static ref readonly Validatable IfScheme(this in Validatable validatable, string scheme) 72 | { 73 | Validator.ThrowIfScheme(validatable.Value, scheme, validatable.ParamName, validatable.ExceptionCustomizations); 74 | 75 | return ref validatable; 76 | } 77 | 78 | /// 79 | /// Throws an exception if scheme of the does not match the given . 80 | /// 81 | /// 82 | /// The default exception thrown is an . 83 | /// 84 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 85 | public static ref readonly Validatable IfSchemeNot(this in Validatable validatable, string scheme) 86 | { 87 | Validator.ThrowIfSchemeNot(validatable.Value, scheme, validatable.ParamName, validatable.ExceptionCustomizations); 88 | 89 | return ref validatable; 90 | } 91 | 92 | /// 93 | /// Throws an exception if scheme of the is absolute. 94 | /// 95 | /// 96 | /// The default exception thrown is an . 97 | /// 98 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 99 | public static ref readonly Validatable IfAbsolute(this in Validatable validatable) 100 | { 101 | Validator.ThrowIfAbsolute(validatable.Value, validatable.ParamName, validatable.ExceptionCustomizations); 102 | 103 | return ref validatable; 104 | } 105 | 106 | /// 107 | /// Throws an exception if scheme of the is relative. 108 | /// 109 | /// 110 | /// The default exception thrown is an . 111 | /// 112 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 113 | public static ref readonly Validatable IfRelative(this in Validatable validatable) 114 | { 115 | Validator.ThrowIfRelative(validatable.Value, validatable.ParamName, validatable.ExceptionCustomizations); 116 | 117 | return ref validatable; 118 | } 119 | 120 | /// 121 | /// Throws an exception if scheme of the is not absolute. 122 | /// 123 | /// 124 | /// The default exception thrown is an . 125 | /// 126 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 127 | public static ref readonly Validatable IfNotAbsolute(this in Validatable validatable) 128 | { 129 | Validator.ThrowIfRelative(validatable.Value, validatable.ParamName, validatable.ExceptionCustomizations); 130 | 131 | return ref validatable; 132 | } 133 | 134 | /// 135 | /// Throws an exception if scheme of the is not relative. 136 | /// 137 | /// 138 | /// The default exception thrown is an . 139 | /// 140 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 141 | public static ref readonly Validatable IfNotRelative(this in Validatable validatable) 142 | { 143 | Validator.ThrowIfAbsolute(validatable.Value, validatable.ParamName, validatable.ExceptionCustomizations); 144 | 145 | return ref validatable; 146 | } 147 | 148 | /// 149 | /// Throws an exception if port of the matches the given . 150 | /// 151 | /// 152 | /// The default exception thrown is an . 153 | /// 154 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 155 | public static ref readonly Validatable IfPort(this in Validatable validatable, int port) 156 | { 157 | Validator.ThrowIfPort(validatable.Value, port, validatable.ParamName, validatable.ExceptionCustomizations); 158 | 159 | return ref validatable; 160 | } 161 | 162 | /// 163 | /// Throws an exception if port of the does not match the given . 164 | /// 165 | /// 166 | /// The default exception thrown is an . 167 | /// 168 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 169 | public static ref readonly Validatable IfPortNot(this in Validatable validatable, int port) 170 | { 171 | Validator.ThrowIfPortNot(validatable.Value, port, validatable.ParamName, validatable.ExceptionCustomizations); 172 | 173 | return ref validatable; 174 | } 175 | 176 | /// 177 | /// Throws an exception if host of the matches the given . 178 | /// 179 | /// 180 | /// The default exception thrown is an . 181 | /// 182 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 183 | public static ref readonly Validatable IfHost(this in Validatable validatable, string host) 184 | { 185 | Validator.ThrowIfHost(validatable.Value, host, validatable.ParamName, validatable.ExceptionCustomizations); 186 | 187 | return ref validatable; 188 | } 189 | 190 | /// 191 | /// Throws an exception if host of the does not match the given . 192 | /// 193 | /// 194 | /// The default exception thrown is an . 195 | /// 196 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 197 | public static ref readonly Validatable IfHostNot(this in Validatable validatable, string host) 198 | { 199 | Validator.ThrowIfHostNot(validatable.Value, host, validatable.ParamName, validatable.ExceptionCustomizations); 200 | 201 | return ref validatable; 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/ValidatableMethods/ValidatableMethods.Types.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | /// 4 | /// Methods for . 5 | /// 6 | public readonly partial record struct Validatable 7 | { 8 | /// 9 | /// Throws an exception if 's runtime type equals . 10 | /// 11 | /// 12 | /// The default exception thrown is an . 13 | /// 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public Validatable IfType() 16 | { 17 | Validator.ThrowIfTypesEqual( 18 | Value.GetType(), 19 | typeof(TOther), 20 | ParamName, 21 | ExceptionCustomizations); 22 | 23 | return this; 24 | } 25 | 26 | /// 27 | /// Throws an exception if 's runtime type does not equal . 28 | /// 29 | /// 30 | /// The default exception thrown is an . 31 | /// 32 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 33 | public Validatable IfNotType() 34 | { 35 | Validator.ThrowIfTypesNotEqual( 36 | Value.GetType(), 37 | typeof(TOther), 38 | ParamName, 39 | ExceptionCustomizations); 40 | 41 | return this; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Validators/Validator.Collections.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | internal static partial class Validator 4 | { 5 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 6 | internal static void ThrowIfCountNot( 7 | TValue value, 8 | int count, 9 | string paramName, 10 | ExceptionCustomizations? exceptionCustomizations, 11 | string? message = null) 12 | where TValue : IEnumerable 13 | { 14 | if (GetCollectionCount(value) != count) 15 | { 16 | ExceptionThrower.Throw( 17 | paramName, 18 | exceptionCustomizations, 19 | message ?? $"Collection count should be equal to {count}."); 20 | } 21 | } 22 | 23 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 24 | internal static void ThrowIfCount( 25 | TValue value, 26 | int count, 27 | string paramName, 28 | ExceptionCustomizations? exceptionCustomizations, 29 | string? message = null) 30 | where TValue : IEnumerable 31 | { 32 | if (GetCollectionCount(value) == count) 33 | { 34 | ExceptionThrower.Throw( 35 | paramName, 36 | exceptionCustomizations, 37 | message ?? $"Collection count should not be equal to {count}."); 38 | } 39 | } 40 | 41 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 42 | internal static void ThrowIfCountGreaterThan( 43 | TValue value, 44 | int count, 45 | string paramName, 46 | ExceptionCustomizations? exceptionCustomizations) 47 | where TValue : IEnumerable 48 | { 49 | if (GetCollectionCount(value) > count) 50 | { 51 | ExceptionThrower.Throw( 52 | paramName, 53 | exceptionCustomizations, 54 | $"Collection count should not be greater than {count}."); 55 | } 56 | } 57 | 58 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 59 | internal static void ThrowIfCountLessThan( 60 | TValue value, 61 | int count, 62 | string paramName, 63 | ExceptionCustomizations? exceptionCustomizations) 64 | where TValue : notnull, IEnumerable 65 | { 66 | if (GetCollectionCount(value) < count) 67 | { 68 | ExceptionThrower.Throw( 69 | paramName, 70 | exceptionCustomizations, 71 | $"Collection count should not be less than {count}."); 72 | } 73 | } 74 | 75 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 76 | internal static void ThrowIfHasNullElements( 77 | TValue value, 78 | string paramName, 79 | ExceptionCustomizations? exceptionCustomizations) 80 | where TValue : IEnumerable 81 | { 82 | foreach (object? item in value) 83 | { 84 | if (item == null) 85 | { 86 | ExceptionThrower.Throw( 87 | paramName, 88 | exceptionCustomizations, 89 | "Collection should not have null elements."); 90 | } 91 | } 92 | } 93 | 94 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 95 | internal static void ThrowIfContainsElement( 96 | TValue value, 97 | TElement element, 98 | string paramName, 99 | ExceptionCustomizations? exceptionCustomizations) 100 | where TValue : IEnumerable 101 | where TElement : notnull 102 | { 103 | if (IsElementInCollection(value, element)) 104 | { 105 | ExceptionThrower.Throw( 106 | paramName, 107 | exceptionCustomizations, 108 | $"Collection should not contain element."); 109 | } 110 | } 111 | 112 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 113 | internal static void ThrowIfNotContainsElement( 114 | TValue value, 115 | TElement element, 116 | string paramName, 117 | ExceptionCustomizations? exceptionCustomizations) 118 | where TValue : IEnumerable 119 | where TElement : notnull 120 | { 121 | if (!IsElementInCollection(value, element)) 122 | { 123 | ExceptionThrower.Throw( 124 | paramName, 125 | exceptionCustomizations, 126 | $"Collection should contain element."); 127 | } 128 | } 129 | 130 | internal static bool IsElementInCollection(TValue value, TElement element) 131 | where TValue : IEnumerable 132 | where TElement : notnull 133 | { 134 | foreach (TElement? item in value) 135 | { 136 | if (element.Equals(item)) 137 | { 138 | return true; 139 | } 140 | } 141 | 142 | return false; 143 | } 144 | 145 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 146 | internal static int GetCollectionCount(TValue value) 147 | where TValue : IEnumerable 148 | { 149 | static int GetEnumeratedCount(IEnumerable enumerable) 150 | { 151 | int count = 0; 152 | IEnumerator enumerator = enumerable.GetEnumerator(); 153 | while (enumerator.MoveNext()) 154 | { 155 | count++; 156 | } 157 | 158 | return count; 159 | } 160 | 161 | return value switch 162 | { 163 | ICollection collection => collection.Count, 164 | string s => s.Length, 165 | _ => GetEnumeratedCount(value) 166 | }; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/Validators/Validator.Comperables.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | internal static partial class Validator 4 | { 5 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 6 | internal static void ThrowIfGreaterThan( 7 | TValue value, 8 | TValue other, 9 | string paramName, 10 | ExceptionCustomizations? exceptionCustomizations = null) 11 | where TValue : notnull, IComparable 12 | { 13 | if (Comparer.Default.Compare(value, other) > 0) 14 | { 15 | ExceptionThrower.ThrowOutOfRange( 16 | paramName, 17 | value, 18 | exceptionCustomizations, 19 | $"Value should not be greater than {other}."); 20 | } 21 | } 22 | 23 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 24 | internal static void ThrowIfGreaterThanOrEqualTo( 25 | TValue value, 26 | TValue other, 27 | string paramName, 28 | ExceptionCustomizations? exceptionCustomizations = null) 29 | where TValue : notnull, IComparable 30 | { 31 | if (Comparer.Default.Compare(value, other) >= 0) 32 | { 33 | ExceptionThrower.ThrowOutOfRange( 34 | paramName, 35 | value, 36 | exceptionCustomizations, 37 | $"Value should not be greater than or equal to {other}."); 38 | } 39 | } 40 | 41 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 42 | internal static void ThrowIfLessThan( 43 | TValue value, 44 | TValue other, 45 | string paramName, 46 | ExceptionCustomizations? exceptionCustomizations = null) 47 | where TValue : notnull, IComparable 48 | { 49 | if (Comparer.Default.Compare(value, other) < 0) 50 | { 51 | ExceptionThrower.ThrowOutOfRange( 52 | paramName, 53 | value, 54 | exceptionCustomizations, 55 | $"Value should not be less than {other}."); 56 | } 57 | } 58 | 59 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 60 | internal static void ThrowIfLessThanOrEqualTo( 61 | TValue value, 62 | TValue other, 63 | string paramName, 64 | ExceptionCustomizations? exceptionCustomizations = null) 65 | where TValue : notnull, IComparable 66 | { 67 | if (Comparer.Default.Compare(value, other) <= 0) 68 | { 69 | ExceptionThrower.ThrowOutOfRange( 70 | paramName, 71 | value, 72 | exceptionCustomizations, 73 | $"Value should not be less than or equal to {other}."); 74 | } 75 | } 76 | 77 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 78 | internal static void ThrowIfNotInRange( 79 | TValue value, 80 | TValue min, 81 | TValue max, 82 | string paramName, 83 | ExceptionCustomizations? exceptionCustomizations = null) 84 | where TValue : notnull, IComparable 85 | { 86 | if (Comparer.Default.Compare(value, min) < 0 || Comparer.Default.Compare(value, max) > 0) 87 | { 88 | ExceptionThrower.ThrowOutOfRange( 89 | paramName, 90 | value, 91 | exceptionCustomizations, 92 | $"Value should be between {min} and {max}."); 93 | } 94 | } 95 | 96 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 97 | internal static void ThrowIfInRange( 98 | TValue value, 99 | TValue min, 100 | TValue max, 101 | string paramName, 102 | ExceptionCustomizations? exceptionCustomizations = null) 103 | where TValue : notnull, IComparable 104 | { 105 | if (Comparer.Default.Compare(value, min) >= 0 && Comparer.Default.Compare(value, max) <= 0) 106 | { 107 | ExceptionThrower.ThrowOutOfRange( 108 | paramName, 109 | value, 110 | exceptionCustomizations, 111 | $"Value should not be between {min} and {max}."); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/Validators/Validator.DateTimes.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | internal static partial class Validator 4 | { 5 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 6 | internal static void ThrowIfNotKind( 7 | DateTime value, 8 | DateTimeKind kind, 9 | string paramName, 10 | ExceptionCustomizations? exceptionCustomizations = null) 11 | { 12 | if (value.Kind != kind) 13 | { 14 | ExceptionThrower.Throw(paramName, exceptionCustomizations, $"Value should be {kind}."); 15 | } 16 | } 17 | 18 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 19 | internal static void ThrowIfKind( 20 | DateTime value, 21 | DateTimeKind kind, 22 | string paramName, 23 | ExceptionCustomizations? exceptionCustomizations = null) 24 | { 25 | if (value.Kind == kind) 26 | { 27 | ExceptionThrower.Throw(paramName, exceptionCustomizations, $"Value should not be {kind}."); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Validators/Validator.Enums.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | internal static partial class Validator 4 | { 5 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 6 | internal static void ThrowIfOutOfRange( 7 | TValue value, 8 | string paramName, 9 | ExceptionCustomizations? exceptionCustomizations = null) 10 | where TValue : struct, Enum 11 | { 12 | if (!Enum.IsDefined(value)) 13 | { 14 | ExceptionThrower.ThrowOutOfRange(paramName, value, exceptionCustomizations, "Value should be defined in enum."); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/Validators/Validator.Equalities.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | internal static partial class Validator 4 | { 5 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 6 | internal static void ThrowIfNotEquals( 7 | TValue value, 8 | TValue other, 9 | string paramName, 10 | ExceptionCustomizations? exceptionCustomizations = null, 11 | string? message = null) 12 | where TValue : notnull 13 | { 14 | if (!EqualityComparer.Default.Equals(value, other)) 15 | { 16 | ExceptionThrower.Throw( 17 | paramName, 18 | exceptionCustomizations, 19 | message ?? $"Value should be equal to {other}."); 20 | } 21 | } 22 | 23 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 24 | internal static void ThrowIfEquals( 25 | TValue value, 26 | TValue other, 27 | string paramName, 28 | ExceptionCustomizations? exceptionCustomizations = null, 29 | string? message = null) 30 | where TValue : notnull 31 | { 32 | if (EqualityComparer.Default.Equals(value, other)) 33 | { 34 | ExceptionThrower.Throw( 35 | paramName, 36 | exceptionCustomizations, 37 | message ?? $"Value should not be equal to {other}."); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/Validators/Validator.Types.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | internal static partial class Validator 4 | { 5 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 6 | internal static void ThrowIfTypesEqual( 7 | Type type, 8 | Type other, 9 | string paramName, 10 | ExceptionCustomizations? exceptionCustomizations) 11 | { 12 | if (type == other) 13 | { 14 | ExceptionThrower.Throw( 15 | paramName, 16 | exceptionCustomizations, 17 | $"Parameter should not be of type '{other.Name}'."); 18 | } 19 | } 20 | 21 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 22 | internal static void ThrowIfTypesNotEqual( 23 | Type type, 24 | Type other, 25 | string paramName, 26 | ExceptionCustomizations? exceptionCustomizations) 27 | { 28 | if (type != other) 29 | { 30 | ExceptionThrower.Throw( 31 | paramName, 32 | exceptionCustomizations, 33 | $"Parameter should be of type '{other.Name}'."); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/Validators/Validator.Uris.cs: -------------------------------------------------------------------------------- 1 | namespace Throw; 2 | 3 | internal static partial class Validator 4 | { 5 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 6 | internal static void ThrowIfSchemeNot( 7 | Uri value, 8 | string scheme, 9 | string paramName, 10 | ExceptionCustomizations? exceptionCustomizations = null) 11 | { 12 | if (!string.Equals(value.Scheme, scheme, StringComparison.OrdinalIgnoreCase)) 13 | { 14 | ExceptionThrower.Throw(paramName, exceptionCustomizations, $"Uri scheme should be {scheme}."); 15 | } 16 | } 17 | 18 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 19 | internal static void ThrowIfScheme( 20 | Uri value, 21 | string scheme, 22 | string paramName, 23 | ExceptionCustomizations? exceptionCustomizations) 24 | { 25 | if (string.Equals(value.Scheme, scheme, StringComparison.OrdinalIgnoreCase)) 26 | { 27 | ExceptionThrower.Throw(paramName, exceptionCustomizations, $"Uri scheme should not be {scheme}."); 28 | } 29 | } 30 | 31 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 32 | internal static void ThrowIfAbsolute( 33 | Uri value, 34 | string paramName, 35 | ExceptionCustomizations? exceptionCustomizations) 36 | { 37 | if (value.IsAbsoluteUri) 38 | { 39 | ExceptionThrower.Throw(paramName, exceptionCustomizations, "Uri should be relative."); 40 | } 41 | } 42 | 43 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 44 | internal static void ThrowIfRelative( 45 | Uri value, 46 | string paramName, 47 | ExceptionCustomizations? exceptionCustomizations) 48 | { 49 | if (!value.IsAbsoluteUri) 50 | { 51 | ExceptionThrower.Throw(paramName, exceptionCustomizations, "Uri should be absolute."); 52 | } 53 | } 54 | 55 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 56 | internal static void ThrowIfPort( 57 | Uri value, 58 | int port, 59 | string paramName, 60 | ExceptionCustomizations? exceptionCustomizations) 61 | { 62 | if (value.Port == port) 63 | { 64 | ExceptionThrower.Throw(paramName, exceptionCustomizations, $"Uri port should not be {port}."); 65 | } 66 | } 67 | 68 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 69 | internal static void ThrowIfPortNot( 70 | Uri value, 71 | int port, 72 | string paramName, 73 | ExceptionCustomizations? exceptionCustomizations) 74 | { 75 | if (value.Port != port) 76 | { 77 | ExceptionThrower.Throw(paramName, exceptionCustomizations, $"Uri port should be {port}."); 78 | } 79 | } 80 | 81 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 82 | internal static void ThrowIfHost( 83 | Uri value, 84 | string host, 85 | string paramName, 86 | ExceptionCustomizations? exceptionCustomizations) 87 | { 88 | if (value.Host == host) 89 | { 90 | ExceptionThrower.Throw(paramName, exceptionCustomizations, $"Uri host should not be {host}."); 91 | } 92 | } 93 | 94 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 95 | internal static void ThrowIfHostNot( 96 | Uri value, 97 | string host, 98 | string paramName, 99 | ExceptionCustomizations? exceptionCustomizations) 100 | { 101 | if (value.Host != host) 102 | { 103 | ExceptionThrower.Throw(paramName, exceptionCustomizations, $"Uri host should be {host}."); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/_usings.cs: -------------------------------------------------------------------------------- 1 | global using System.Collections; 2 | global using System.Diagnostics.CodeAnalysis; 3 | global using System.Diagnostics.Contracts; 4 | global using System.Runtime.CompilerServices; 5 | global using OneOf; 6 | -------------------------------------------------------------------------------- /src/stylecop.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", 3 | "settings": { 4 | "orderingRules": { 5 | "usingDirectivesPlacement": "outsideNamespace" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /tests/UnitTests/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # CA1707: Identifiers should not contain underscores 4 | dotnet_diagnostic.CA1707.severity = none 5 | 6 | # IDE0058: Expression value is never used 7 | dotnet_diagnostic.IDE0058.severity = none 8 | 9 | # IDE0008: Use explicit type 10 | dotnet_diagnostic.IDE0008.severity = none 11 | 12 | # SA1122: Use string.Empty for empty strings 13 | dotnet_diagnostic.SA1122.severity = none 14 | 15 | # SA1200: Using directives should be placed correctly 16 | dotnet_diagnostic.SA1200.severity = none 17 | 18 | # SA1201: Elements should appear in the correct order 19 | dotnet_diagnostic.SA1201.severity = none 20 | 21 | # CS1591: Missing XML comment for publicly visible type or member 22 | dotnet_diagnostic.CS1591.severity = none 23 | -------------------------------------------------------------------------------- /tests/UnitTests/Common/ValidatableTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.Common; 2 | 3 | [TestClass] 4 | public class ValidatableTests 5 | { 6 | [TestMethod] 7 | public void CastValidatable_WhenToOriginalType_ShouldReturnOriginalValue() 8 | { 9 | // Arrange 10 | string value = "value"; 11 | 12 | // Act 13 | string castedValue = value.Throw(); 14 | 15 | // Assert 16 | castedValue.Should().Be(value); 17 | } 18 | 19 | [TestMethod] 20 | public void UpdateExceptionCustomization_WhenToDefault_ShouldReturnValidatableWithDefaultCustomization() 21 | { 22 | // Arrange 23 | string value = "value"; 24 | var validatable = value.Throw("custom message"); // some customization. 25 | 26 | // Act 27 | Validatable result = validatable.Throw(); // reset back to default. 28 | 29 | // Assert 30 | result.ExceptionCustomizations.Should().BeNull(); 31 | } 32 | 33 | [TestMethod] 34 | public void UpdateExceptionCustomization_WhenToCustomMessage_ShouldReturnValidatableWithCustomMessageCustomization() 35 | { 36 | // Arrange 37 | string value = "value"; 38 | var validatable = value.Throw(); // no customization. 39 | 40 | // Act 41 | Validatable result = validatable.Throw("custom message"); // update to custom message. 42 | 43 | // Assert 44 | result.ExceptionCustomizations.Should().NotBeNull(); 45 | result.ExceptionCustomizations!.Value.Customization.Value 46 | .Should().BeOfType() 47 | .Subject.Should().BeSameAs("custom message"); 48 | } 49 | 50 | [TestMethod] 51 | public void UpdateExceptionCustomization_WhenToCustomThrower_ShouldReturnValidatableWithCustomThrowerCustomization() 52 | { 53 | // Arrange 54 | string value = "value"; 55 | var validatable = value.Throw(); // no customization. 56 | var exceptionThrower = () => new Exception(); 57 | 58 | // Act 59 | Validatable result = validatable.Throw(exceptionThrower); // update to custom thrower. 60 | 61 | // Assert 62 | result.ExceptionCustomizations.Should().NotBeNull(); 63 | result.ExceptionCustomizations!.Value.Customization.Value 64 | .Should().BeOfType>() 65 | .Subject.Should().BeSameAs(exceptionThrower); 66 | } 67 | 68 | [TestMethod] 69 | public void UpdateExceptionCustomization_WhenToCustomThrowerWithParamName_ShouldReturnValidatableWithCustomThrowerCustomization() 70 | { 71 | // Arrange 72 | string value = "value"; 73 | var validatable = value.Throw(); // no customization. 74 | Func exceptionThrower = paramName => new Exception($"param: {paramName}"); 75 | 76 | // Act 77 | Validatable result = validatable.Throw(exceptionThrower); // update to custom thrower. 78 | 79 | // Assert 80 | result.ExceptionCustomizations.Should().NotBeNull(); 81 | result.ExceptionCustomizations!.Value.Customization.Value 82 | .Should().BeOfType>() 83 | .Subject.Should().BeSameAs(exceptionThrower); 84 | } 85 | 86 | [TestMethod] 87 | public void UpdateExceptionCustomization_WhenToExceptionType_ShouldReturnValidatableWithExceptionTypeCustomization() 88 | { 89 | // Arrange 90 | string value = "value"; 91 | var validatable = value.Throw(); // no customization. 92 | 93 | // Act 94 | Validatable result = validatable.Throw(); // update to custom exception type. 95 | 96 | // Assert 97 | result.ExceptionCustomizations.Should().NotBeNull(); 98 | result.ExceptionCustomizations!.Value.Customization.Value 99 | .Should().BeSameAs(typeof(InvalidOperationException)); 100 | } 101 | } -------------------------------------------------------------------------------- /tests/UnitTests/Throw.UnitTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/UnitTests/Utils/ParameterConstants.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.Utils; 2 | 3 | public static class ParameterConstants 4 | { 5 | public const string ParamName = "paramName"; 6 | public const string ActualValue = "actualValue"; 7 | public const string CustomMessage = "custom message"; 8 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableCreation/ValidatableCreationExtensions.NullablesTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.ValidatableCreation; 2 | 3 | [TestClass] 4 | public class ValidatableCreationExtensionsNullablesTests 5 | { 6 | [TestMethod] 7 | public void CreateThrowableFromNullable_WhenNull_ShouldThrowArgumentNullException() 8 | { 9 | // Arrange 10 | string? value = null; 11 | 12 | // Act 13 | Action action = () => value.ThrowIfNull(); 14 | 15 | // Assert 16 | action.Should().ThrowExactly(); 17 | } 18 | 19 | [TestMethod] 20 | public void CreateThrowableFromNullable_WhenNoCustomizations_ShouldCreateCorrespondingThrowarble() 21 | { 22 | // Arrange 23 | string? value = "value"; 24 | 25 | // Act 26 | Validatable result = value.ThrowIfNull(); 27 | 28 | // Assert 29 | result.Value.Should().Be(value); 30 | result.ExceptionCustomizations.Should().BeNull(); 31 | result.ParamName.Should().Be(nameof(value)); 32 | } 33 | 34 | [TestMethod] 35 | public void CreateThrowableFromNullable_WhenCustomExceptionMessage_ShouldCreateCorrespondingThrowarble() 36 | { 37 | // Arrange 38 | string? value = "value"; 39 | 40 | // Act 41 | Validatable result = value.ThrowIfNull(ParameterConstants.CustomMessage); 42 | 43 | // Assert 44 | result.Value.Should().Be(value); 45 | result.ExceptionCustomizations.Should().NotBeNull(); 46 | result.ExceptionCustomizations!.Value.Customization.Value 47 | .Should().BeOfType() 48 | .Subject.Should().BeSameAs(ParameterConstants.CustomMessage); 49 | result.ParamName.Should().Be(nameof(value)); 50 | } 51 | 52 | [TestMethod] 53 | public void CreateThrowableFromNullable_WhenCustomExceptionThrower_ShouldCreateCorrespondingThrowarble() 54 | { 55 | // Arrange 56 | string? value = "value"; 57 | var exceptionThrower = () => new Exception(); 58 | 59 | // Act 60 | Validatable result = value.ThrowIfNull(exceptionThrower); 61 | 62 | // Assert 63 | result.Value.Should().Be(value); 64 | result.ExceptionCustomizations.Should().NotBeNull(); 65 | result.ExceptionCustomizations!.Value.Customization.Value 66 | .Should().BeOfType>() 67 | .Subject.Should().BeSameAs(exceptionThrower); 68 | result.ParamName.Should().Be(nameof(value)); 69 | } 70 | 71 | [TestMethod] 72 | public void CreateThrowableFromNullable_WhenCustomExceptionThrowerWithParamName_ShouldCreateCorrespondingThrowarble() 73 | { 74 | // Arrange 75 | string? value = "value"; 76 | Func exceptionThrower = paramName => new Exception($"param: {paramName}"); 77 | 78 | // Act 79 | Validatable result = value.ThrowIfNull(exceptionThrower); 80 | 81 | // Assert 82 | result.Value.Should().Be(value); 83 | result.ExceptionCustomizations.Should().NotBeNull(); 84 | result.ExceptionCustomizations!.Value.Customization.Value 85 | .Should().BeOfType>() 86 | .Subject.Should().BeSameAs(exceptionThrower); 87 | result.ParamName.Should().Be(nameof(value)); 88 | } 89 | 90 | [TestMethod] 91 | public void CreateThrowableFromValueTypeNullable_WhenNull_ShouldThrowArgumentNullException() 92 | { 93 | // Arrange 94 | int? value = null; 95 | 96 | // Act 97 | Action action = () => value.ThrowIfNull(); 98 | 99 | // Assert 100 | action.Should().ThrowExactly(); 101 | } 102 | 103 | [TestMethod] 104 | public void CreateThrowableFromValueTypeNullable_WhenNoCustomizations_ShouldCreateCorrespondingThrowarble() 105 | { 106 | // Arrange 107 | int? value = 5; 108 | 109 | // Act 110 | Validatable result = value.ThrowIfNull(); 111 | 112 | // Assert 113 | result.Value.Should().Be(value); 114 | result.ExceptionCustomizations.Should().BeNull(); 115 | result.ParamName.Should().Be(nameof(value)); 116 | } 117 | 118 | [TestMethod] 119 | public void CreateThrowableFromValueTypeNullable_WhenCustomExceptionMessage_ShouldCreateCorrespondingThrowarble() 120 | { 121 | // Arrange 122 | int? value = 5; 123 | 124 | // Act 125 | Validatable result = value.ThrowIfNull(ParameterConstants.CustomMessage); 126 | 127 | // Assert 128 | result.Value.Should().Be(value); 129 | result.ExceptionCustomizations.Should().NotBeNull(); 130 | result.ExceptionCustomizations!.Value.Customization.Value 131 | .Should().BeOfType() 132 | .Subject.Should().BeSameAs(ParameterConstants.CustomMessage); 133 | result.ParamName.Should().Be(nameof(value)); 134 | } 135 | 136 | [TestMethod] 137 | public void CreateThrowableFromValueTypeNullable_WhenCustomExceptionThrower_ShouldCreateCorrespondingThrowarble() 138 | { 139 | // Arrange 140 | int? value = 5; 141 | var exceptionThrower = () => new Exception(); 142 | 143 | // Act 144 | Validatable result = value.ThrowIfNull(exceptionThrower); 145 | 146 | // Assert 147 | result.Value.Should().Be(value); 148 | result.ExceptionCustomizations.Should().NotBeNull(); 149 | result.ExceptionCustomizations!.Value.Customization.Value 150 | .Should().BeOfType>() 151 | .Subject.Should().BeSameAs(exceptionThrower); 152 | result.ParamName.Should().Be(nameof(value)); 153 | } 154 | 155 | [TestMethod] 156 | public void CreateThrowableFromValueTypeNullable_WhenCustomExceptionThrowerWithParamName_ShouldCreateCorrespondingThrowarble() 157 | { 158 | // Arrange 159 | int? value = 5; 160 | Func exceptionThrower = paramName => new Exception($"param: {paramName}"); 161 | 162 | // Act 163 | Validatable result = value.ThrowIfNull(exceptionThrower); 164 | 165 | // Assert 166 | result.Value.Should().Be(value); 167 | result.ExceptionCustomizations.Should().NotBeNull(); 168 | result.ExceptionCustomizations!.Value.Customization.Value 169 | .Should().BeOfType>() 170 | .Subject.Should().BeSameAs(exceptionThrower); 171 | result.ParamName.Should().Be(nameof(value)); 172 | } 173 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableCreation/ValidatableCreationExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.ValidatableCreation; 2 | 3 | using OneOf; 4 | 5 | [TestClass] 6 | public class ValidatableCreationExtensionsTests 7 | { 8 | [TestMethod] 9 | public void CreateThrowable_WhenNoCustomizations_ShouldCreateCorrespondingThrowarble() 10 | { 11 | // Arrange 12 | var value = "value"; 13 | 14 | // Act 15 | Validatable result = value.Throw(); 16 | 17 | // Assert 18 | result.Value.Should().Be(value); 19 | result.ExceptionCustomizations.Should().BeNull(); 20 | result.ParamName.Should().Be(nameof(value)); 21 | } 22 | 23 | [TestMethod] 24 | public void CreateThrowable_WhenCustomExceptionMessage_ShouldCreateCorrespondingThrowarble() 25 | { 26 | // Arrange 27 | var value = "value"; 28 | 29 | // Act 30 | Validatable result = value.Throw(ParameterConstants.CustomMessage); 31 | 32 | // Assert 33 | result.Value.Should().Be(value); 34 | result.ExceptionCustomizations.Should().NotBeNull(); 35 | result.ExceptionCustomizations!.Value.Customization.Value 36 | .Should().BeOfType() 37 | .Subject.Should().BeSameAs(ParameterConstants.CustomMessage); 38 | result.ParamName.Should().Be(nameof(value)); 39 | } 40 | 41 | [TestMethod] 42 | public void CreateThrowable_WhenCustomExceptionThrower_ShouldCreateCorrespondingThrowarble() 43 | { 44 | // Arrange 45 | var value = "value"; 46 | var exceptionThrower = () => new Exception(); 47 | 48 | // Act 49 | Validatable result = value.Throw(exceptionThrower); 50 | 51 | // Assert 52 | result.Value.Should().Be(value); 53 | result.ExceptionCustomizations.Should().NotBeNull(); 54 | result.ExceptionCustomizations!.Value.Customization.Value 55 | .Should().BeOfType>() 56 | .Subject.Should().BeSameAs(exceptionThrower); 57 | result.ParamName.Should().Be(nameof(value)); 58 | } 59 | 60 | [TestMethod] 61 | public void CreateThrowable_WhenCustomExceptionThrowerWithParamName_ShouldCreateCorrespondingThrowarble() 62 | { 63 | // Arrange 64 | var value = "value"; 65 | Func exceptionThrower = paramName => new Exception($"param: {paramName}"); 66 | 67 | // Act 68 | Validatable result = value.Throw(exceptionThrower); 69 | 70 | // Assert 71 | result.Value.Should().Be(value); 72 | result.ExceptionCustomizations.Should().NotBeNull(); 73 | result.ExceptionCustomizations!.Value.Customization.Value 74 | .Should().BeOfType>() 75 | .Subject.Should().BeSameAs(exceptionThrower); 76 | result.ParamName.Should().Be(nameof(value)); 77 | } 78 | 79 | [TestMethod] 80 | public void CreateThrowable_WhenOneOfDiscriminatedUnion_ShouldCreateCorrespondingThrowarble() 81 | { 82 | // Arrange 83 | var value = "value"; 84 | OneOf, Func> customizations = ParameterConstants.CustomMessage; 85 | 86 | // Act 87 | Validatable result = value.Throw(customizations); 88 | 89 | // Assert 90 | result.Value.Should().Be(value); 91 | result.ExceptionCustomizations.Should().NotBeNull(); 92 | result.ExceptionCustomizations!.Value.Customization.Value 93 | .Should().BeOfType() 94 | .Subject.Should().BeSameAs(ParameterConstants.CustomMessage); 95 | result.ParamName.Should().Be(nameof(value)); 96 | } 97 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableExtensions/StringProperties/ValidatableExtensions.StringProperties.LengthTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.ValidatableExtensions.StringProperties; 2 | 3 | [TestClass] 4 | public class StringPropertiesLengthTests 5 | { 6 | [TestMethod] 7 | public void ThrowIfPropertyLongerThan_WhenPropertyIsLongerThan_ShouldThrow() 8 | { 9 | // Arrange 10 | var person = new { Name = "Amichai" }; 11 | 12 | // Act 13 | Action action = () => person.Throw().IfLongerThan(p => p.Name, 3); 14 | 15 | // Assert 16 | action.Should().ThrowExactly() 17 | .WithMessage($"String should not be longer than 3 characters. (Parameter '{nameof(person)}: p => p.Name')"); 18 | } 19 | 20 | [TestMethod] 21 | public void ThrowIfPropertyLongerThan_WhenPropertyIsNotLongerThan_ShouldNotThrow() 22 | { 23 | // Arrange 24 | var person = new { Name = "Amichai" }; 25 | 26 | // Act 27 | Action action = () => person.Throw().IfLongerThan(p => p.Name, 10); 28 | 29 | // Assert 30 | action.Should().NotThrow(); 31 | } 32 | 33 | [TestMethod] 34 | public void ThrowIfPropertyShorterThan_WhenPropertyIsShorterThan_ShouldThrow() 35 | { 36 | // Arrange 37 | var person = new { Name = "Amichai" }; 38 | 39 | // Act 40 | Action action = () => person.Throw().IfShorterThan(p => p.Name, 10); 41 | 42 | // Assert 43 | action.Should().ThrowExactly() 44 | .WithMessage($"String should not be shorter than 10 characters. (Parameter '{nameof(person)}: p => p.Name')"); 45 | } 46 | 47 | [TestMethod] 48 | public void ThrowIfPropertyShorterThan_WhenPropertyIsNotShorterThan_ShouldNotThrow() 49 | { 50 | // Arrange 51 | var person = new { Name = "Amichai" }; 52 | 53 | // Act 54 | Action action = () => person.Throw().IfShorterThan(p => p.Name, 3); 55 | 56 | // Assert 57 | action.Should().NotThrow(); 58 | } 59 | 60 | [TestMethod] 61 | public void ThrowIfPropertyLengthEquals_WhenPropertyLengthEquals_ShouldThrow() 62 | { 63 | // Arrange 64 | var person = new { Name = "Amichai" }; 65 | 66 | // Act 67 | Action action = () => person.Throw().IfLengthEquals(p => p.Name, 7); 68 | 69 | // Assert 70 | action.Should().ThrowExactly() 71 | .WithMessage($"String length should not be equal to 7. (Parameter '{nameof(person)}: p => p.Name')"); 72 | } 73 | 74 | [TestMethod] 75 | public void ThrowIfPropertyLengthEquals_WhenPropertyLengthNotEquals_ShouldNotThrow() 76 | { 77 | // Arrange 78 | var person = new { Name = "Amichai" }; 79 | 80 | // Act 81 | Action action = () => person.Throw().IfLengthEquals(p => p.Name, 100); 82 | 83 | // Assert 84 | action.Should().NotThrow(); 85 | } 86 | 87 | [TestMethod] 88 | public void ThrowIfPropertyLengthNotEquals_WhenPropertyLengthNotEquals_ShouldThrow() 89 | { 90 | // Arrange 91 | var person = new { Name = "Amichai" }; 92 | 93 | // Act 94 | Action action = () => person.Throw().IfLengthNotEquals(p => p.Name, 100); 95 | 96 | // Assert 97 | action.Should().ThrowExactly() 98 | .WithMessage($"String length should be equal to 100. (Parameter '{nameof(person)}: p => p.Name')"); 99 | } 100 | 101 | [TestMethod] 102 | public void ThrowIfPropertyLengthNotEquals_WhenPropertyLengthEquals_ShouldNotThrow() 103 | { 104 | // Arrange 105 | var person = new { Name = "Amichai" }; 106 | 107 | // Act 108 | Action action = () => person.Throw().IfLengthNotEquals(p => p.Name, 7); 109 | 110 | // Assert 111 | action.Should().NotThrow(); 112 | } 113 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableExtensions/StringProperties/ValidatableExtensions.StringProperties.RegexTests.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace Throw.UnitTests.ValidatableExtensions.StringProperties; 4 | 5 | [TestClass] 6 | public class StringPropertiesRegexTests 7 | { 8 | [DataTestMethod] 9 | [DataRow("Amichai", @"[a-zA-Z]", RegexOptions.None)] 10 | [DataRow("Haman", @"\b[H]\w+", RegexOptions.None)] 11 | [DataRow("My Name", @"\bname\b", RegexOptions.IgnoreCase)] 12 | public void ThrowIfPropertyMatches_WhenPropertyMatchesRegexPattern_ShouldThrow(string value, string regexPattern, RegexOptions regexOptions) 13 | { 14 | // Arrange 15 | var person = new { Name = value }; 16 | 17 | // Act 18 | Action action = () => person.Throw().IfMatches(p => p.Name, regexPattern, regexOptions); 19 | 20 | // Assert 21 | action.Should() 22 | .ThrowExactly() 23 | .WithMessage($"String should not match RegEx pattern '{regexPattern}' (Parameter '{nameof(person)}: p => p.Name')"); 24 | } 25 | 26 | [DataTestMethod] 27 | [DataRow("123456789", @"[a-zA-Z]", RegexOptions.None)] 28 | [DataRow("Amichai", @"\b[H]\w+", RegexOptions.None)] 29 | [DataRow("No Match", @"\bname\b", RegexOptions.IgnoreCase)] 30 | public void ThrowIfPropertyMatches_WhenPropertyNotMatchesRegexPattern_ShouldNotThrow(string value, string regexPattern, RegexOptions regexOptions) 31 | { 32 | // Arrange 33 | var person = new { Name = value }; 34 | 35 | // Act 36 | Action action = () => person.Throw().IfMatches(p => p.Name, regexPattern, regexOptions); 37 | 38 | // Assert 39 | action.Should().NotThrow(); 40 | } 41 | 42 | [DataTestMethod] 43 | [DataRow("Amichai", @"[a-zA-Z]", RegexOptions.None)] 44 | [DataRow("Haman", @"\b[H]\w+", RegexOptions.None)] 45 | [DataRow("My Name", @"\bname\b", RegexOptions.IgnoreCase)] 46 | public void ThrowIfPropertyMatches_WhenPropertyMatchesRegex_ShouldThrow(string value, string regexPattern, RegexOptions regexOptions) 47 | { 48 | // Arrange 49 | var person = new { Name = value }; 50 | var regex = new Regex(regexPattern, regexOptions); 51 | 52 | // Act 53 | Action action = () => person.Throw().IfMatches(p => p.Name, regex); 54 | 55 | // Assert 56 | action.Should() 57 | .ThrowExactly() 58 | .WithMessage($"String should not match RegEx pattern '{regex}' (Parameter '{nameof(person)}: p => p.Name')"); 59 | } 60 | 61 | [DataTestMethod] 62 | [DataRow("123456789", @"[a-zA-Z]", RegexOptions.None)] 63 | [DataRow("Amichai", @"\b[H]\w+", RegexOptions.None)] 64 | [DataRow("No Match", @"\bname\b", RegexOptions.IgnoreCase)] 65 | public void ThrowIfPropertyMatches_WhenPropertyNotMatchesRegex_ShouldNotThrow(string value, string regexPattern, RegexOptions regexOptions) 66 | { 67 | // Arrange 68 | var person = new { Name = value }; 69 | var regex = new Regex(regexPattern, regexOptions); 70 | 71 | // Act 72 | Action action = () => person.Throw().IfMatches(p => p.Name, regex); 73 | 74 | // Assert 75 | action.Should().NotThrow(); 76 | } 77 | 78 | [DataTestMethod] 79 | [DataRow("123456789", @"[a-zA-Z]", RegexOptions.None)] 80 | [DataRow("Amichai", @"\b[H]\w+", RegexOptions.None)] 81 | [DataRow("No Match", @"\bname\b", RegexOptions.IgnoreCase)] 82 | public void ThrowIfPropertyNotMatches_WhenPropertyNotMatchesRegexPattern_ShouldThrow(string value, string regexPattern, RegexOptions regexOptions) 83 | { 84 | // Arrange 85 | var person = new { Name = value }; 86 | 87 | // Act 88 | Action action = () => person.Throw().IfNotMatches(p => p.Name, regexPattern, regexOptions); 89 | 90 | // Assert 91 | action.Should() 92 | .ThrowExactly() 93 | .WithMessage($"String should match RegEx pattern '{regexPattern}' (Parameter '{nameof(person)}: p => p.Name')"); 94 | } 95 | 96 | [DataTestMethod] 97 | [DataRow("Amichai", @"[a-zA-Z]", RegexOptions.None)] 98 | [DataRow("Haman", @"\b[H]\w+", RegexOptions.None)] 99 | [DataRow("My Name", @"\bname\b", RegexOptions.IgnoreCase)] 100 | public void ThrowIfPropertyNotMatches_WhenPropertyMatchesRegexPattern_ShouldNotThrow(string value, string regexPattern, RegexOptions regexOptions) 101 | { 102 | // Arrange 103 | var person = new { Name = value }; 104 | 105 | // Act 106 | Action action = () => person.Throw().IfNotMatches(p => p.Name, regexPattern, regexOptions); 107 | 108 | // Assert 109 | action.Should().NotThrow(); 110 | } 111 | 112 | [DataTestMethod] 113 | [DataRow("123456789", @"[a-zA-Z]", RegexOptions.None)] 114 | [DataRow("Amichai", @"\b[H]\w+", RegexOptions.None)] 115 | [DataRow("No Match", @"\bname\b", RegexOptions.IgnoreCase)] 116 | public void ThrowIfPropertyNotMatches_WhenPropertyNotMatchesRegex_ShouldThrow(string value, string regexPattern, RegexOptions regexOptions) 117 | { 118 | // Arrange 119 | var person = new { Name = value }; 120 | var regex = new Regex(regexPattern, regexOptions); 121 | 122 | // Act 123 | Action action = () => person.Throw().IfNotMatches(p => p.Name, regex); 124 | 125 | // Assert 126 | action.Should() 127 | .ThrowExactly() 128 | .WithMessage($"String should match RegEx pattern '{regex}' (Parameter '{nameof(person)}: p => p.Name')"); 129 | } 130 | 131 | [DataTestMethod] 132 | [DataRow("Amichai", @"[a-zA-Z]", RegexOptions.None)] 133 | [DataRow("Haman", @"\b[H]\w+", RegexOptions.None)] 134 | [DataRow("My Name", @"\bname\b", RegexOptions.IgnoreCase)] 135 | public void ThrowIfPropertyNotMatches_WhenPropertyMatchesRegex_ShouldNotThrow(string value, string regexPattern, RegexOptions regexOptions) 136 | { 137 | // Arrange 138 | var person = new { Name = value }; 139 | var regex = new Regex(regexPattern, regexOptions); 140 | 141 | // Act 142 | Action action = () => person.Throw().IfNotMatches(p => p.Name, regex); 143 | 144 | // Assert 145 | action.Should().NotThrow(); 146 | } 147 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableExtensions/Strings/ValidatableExtensions.Strings.EqualityTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.ValidatableExtensions.Strings; 2 | 3 | [TestClass] 4 | public class StringEqualityTests 5 | { 6 | [TestMethod] 7 | public void ThrowIfWhiteSpace_WhenWhiteSpace_ShouldThrow() 8 | { 9 | // Arrange 10 | string value = " "; 11 | 12 | // Act 13 | Action action = () => value.Throw().IfWhiteSpace(); 14 | 15 | // Assert 16 | action.Should() 17 | .ThrowExactly() 18 | .WithMessage($"String should not be white space only. (Parameter '{nameof(value)}')"); 19 | } 20 | 21 | [TestMethod] 22 | public void ThrowIfWhiteSpace_WhenNotWhiteSpace_ShouldNotThrow() 23 | { 24 | // Arrange 25 | string value = "not white space"; 26 | 27 | // Act 28 | Action action = () => value.Throw().IfWhiteSpace(); 29 | 30 | // Assert 31 | action.Should().NotThrow(); 32 | } 33 | 34 | [TestMethod] 35 | public void ThrowIfEmpty_WhenEmpty_ShouldThrow() 36 | { 37 | // Arrange 38 | string value = ""; 39 | 40 | // Act 41 | Action action = () => value.Throw().IfEmpty(); 42 | 43 | // Assert 44 | action.Should() 45 | .ThrowExactly() 46 | .WithMessage($"String should not be empty. (Parameter '{nameof(value)}')"); 47 | } 48 | 49 | [TestMethod] 50 | public void ThrowIfEmpty_WhenNotEmpty_ShouldNotThrow() 51 | { 52 | // Arrange 53 | string value = "not empty"; 54 | 55 | // Act 56 | Action action = () => value.Throw().IfEmpty(); 57 | 58 | // Assert 59 | action.Should().NotThrow(); 60 | } 61 | 62 | [TestMethod] 63 | public void ThrowIfEquals_WhenEquals_ShouldThrow() 64 | { 65 | // Arrange 66 | string value = "value"; 67 | 68 | // Act 69 | Action action = () => value.Throw().IfEquals("value"); 70 | 71 | // Assert 72 | action.Should() 73 | .ThrowExactly() 74 | .WithMessage($"String should not be equal to 'value' (comparison type: '{StringComparison.Ordinal}'). (Parameter '{nameof(value)}')"); 75 | } 76 | 77 | [TestMethod] 78 | public void ThrowIfEquals_WhenNotEquals_ShouldNotThrow() 79 | { 80 | // Arrange 81 | string value = "value"; 82 | 83 | // Act 84 | Action action = () => value.Throw().IfEquals("VALUE"); 85 | 86 | // Assert 87 | action.Should().NotThrow(); 88 | } 89 | 90 | [DataTestMethod] 91 | [DataRow("value", "VALUE", StringComparison.OrdinalIgnoreCase)] 92 | [DataRow("\u0061\u030a", "\u00e5", StringComparison.InvariantCulture)] 93 | [DataRow("AA", "A\u0000\u0000\u0000a", StringComparison.InvariantCultureIgnoreCase)] 94 | public void ThrowIfEquals_WhenEqualsUsingCustomComparisonType_ShouldThrow(string value, string otherValue, StringComparison comparisonType) 95 | { 96 | // Act 97 | Action action = () => value.Throw().IfEquals(otherValue, comparisonType); 98 | 99 | // Assert 100 | action.Should() 101 | .ThrowExactly() 102 | .WithMessage($"String should not be equal to '{otherValue}' (comparison type: '{comparisonType}'). (Parameter '{nameof(value)}')"); 103 | } 104 | 105 | [DataTestMethod] 106 | [DataRow("value", "different value", StringComparison.OrdinalIgnoreCase)] 107 | [DataRow("\u0061\u030a", "different value", StringComparison.InvariantCulture)] 108 | [DataRow("AA", "different value", StringComparison.InvariantCultureIgnoreCase)] 109 | public void ThrowIfEquals_WhenNotEqualsUsingCustomComparisonType_ShouldNotThrow(string value, string otherValue, StringComparison comparisonType) 110 | { 111 | // Act 112 | Action action = () => value.Throw().IfEquals(otherValue, comparisonType); 113 | 114 | // Assert 115 | action.Should().NotThrow(); 116 | } 117 | 118 | [TestMethod] 119 | public void ThrowIfEqualsIgnoreCase_WhenEqualsSameCase_ShouldThrow() 120 | { 121 | // Arrange 122 | string value = "value"; 123 | 124 | // Act 125 | Action action = () => value.Throw().IfEqualsIgnoreCase("value"); 126 | 127 | // Assert 128 | action.Should() 129 | .ThrowExactly() 130 | .WithMessage($"String should not be equal to 'value' (comparison type: '{StringComparison.OrdinalIgnoreCase}'). (Parameter '{nameof(value)}')"); 131 | } 132 | 133 | [TestMethod] 134 | public void ThrowIfEqualsIgnoreCase_WhenEqualsDifferentCase_ShouldThrow() 135 | { 136 | // Arrange 137 | string value = "value"; 138 | 139 | // Act 140 | Action action = () => value.Throw().IfEqualsIgnoreCase("VALUE"); 141 | 142 | // Assert 143 | action.Should() 144 | .ThrowExactly() 145 | .WithMessage($"String should not be equal to 'VALUE' (comparison type: '{StringComparison.OrdinalIgnoreCase}'). (Parameter '{nameof(value)}')"); 146 | } 147 | 148 | [TestMethod] 149 | public void ThrowIfEqualsIgnoreCase_WhenNotEquals_ShouldNotThrow() 150 | { 151 | // Arrange 152 | string value = "value"; 153 | 154 | // Act 155 | Action action = () => value.Throw().IfEqualsIgnoreCase("different value"); 156 | 157 | // Assert 158 | action.Should().NotThrow(); 159 | } 160 | 161 | [TestMethod] 162 | public void ThrowIfNotEquals_WhenNotEquals_ShouldThrow() 163 | { 164 | // Arrange 165 | string value = "value"; 166 | 167 | // Act 168 | Action action = () => value.Throw().IfNotEquals("different value"); 169 | 170 | // Assert 171 | action.Should() 172 | .ThrowExactly() 173 | .WithMessage($"String should be equal to 'different value' (comparison type: '{StringComparison.Ordinal}'). (Parameter '{nameof(value)}')"); 174 | } 175 | 176 | [DataTestMethod] 177 | [DataRow("value", "VALUE", StringComparison.OrdinalIgnoreCase)] 178 | [DataRow("\u0061\u030a", "\u00e5", StringComparison.InvariantCulture)] 179 | [DataRow("AA", "A\u0000\u0000\u0000a", StringComparison.InvariantCultureIgnoreCase)] 180 | public void ThrowIfNotEquals_WhenEqualsUsingCustomComparisonType_ShouldNotThrow(string value, string otherValue, StringComparison comparisonType) 181 | { 182 | // Act 183 | Action action = () => value.Throw().IfNotEquals(otherValue, comparisonType); 184 | 185 | // Assert 186 | action.Should().NotThrow(); 187 | } 188 | 189 | [DataTestMethod] 190 | [DataRow("value", "different value", StringComparison.OrdinalIgnoreCase)] 191 | [DataRow("\u0061\u030a", "different value", StringComparison.InvariantCulture)] 192 | [DataRow("AA", "different value", StringComparison.InvariantCultureIgnoreCase)] 193 | public void ThrowIfNotEquals_WhenNotEqualsUsingCustomComparisonType_ShouldThrow(string value, string otherValue, StringComparison comparisonType) 194 | { 195 | // Act 196 | Action action = () => value.Throw().IfNotEquals(otherValue, comparisonType); 197 | 198 | // Assert 199 | action.Should() 200 | .ThrowExactly() 201 | .WithMessage($"String should be equal to '{otherValue}' (comparison type: '{comparisonType}'). (Parameter '{nameof(value)}')"); 202 | } 203 | 204 | [TestMethod] 205 | public void ThrowIfNotEquals_WhenEquals_ShouldNotThrow() 206 | { 207 | // Arrange 208 | string value = "value"; 209 | 210 | // Act 211 | Action action = () => value.Throw().IfNotEquals("value"); 212 | 213 | // Assert 214 | action.Should().NotThrow(); 215 | } 216 | 217 | [TestMethod] 218 | public void ThrowIfNotEqualsIgnoreCase_WhenNotEquals_ShouldThrow() 219 | { 220 | // Arrange 221 | string value = "value"; 222 | 223 | // Act 224 | Action action = () => value.Throw().IfNotEqualsIgnoreCase("different value"); 225 | 226 | // Assert 227 | action.Should() 228 | .ThrowExactly() 229 | .WithMessage($"String should be equal to 'different value' (comparison type: '{StringComparison.OrdinalIgnoreCase}'). (Parameter '{nameof(value)}')"); 230 | } 231 | 232 | [TestMethod] 233 | public void ThrowIfNotEqualsIgnoreCase_WhenEquals_ShouldNotThrow() 234 | { 235 | // Arrange 236 | string value = "value"; 237 | 238 | // Act 239 | Action action = () => value.Throw().IfNotEqualsIgnoreCase("value"); 240 | 241 | // Assert 242 | action.Should().NotThrow(); 243 | } 244 | 245 | [TestMethod] 246 | public void ThrowIfNotEqualsIgnoreCase_WhenEqualsDifferentCase_ShouldNotThrow() 247 | { 248 | // Arrange 249 | string value = "value"; 250 | 251 | // Act 252 | Action action = () => value.Throw().IfNotEqualsIgnoreCase("VALUE"); 253 | 254 | // Assert 255 | action.Should().NotThrow(); 256 | } 257 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableExtensions/Strings/ValidatableExtensions.Strings.LengthTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.ValidatableExtensions.Strings; 2 | 3 | [TestClass] 4 | public class StringLengthTests 5 | { 6 | [TestMethod] 7 | public void ThrowIfLongerThan_WhenLongerThan_ShouldThrow() 8 | { 9 | // Arrange 10 | string value = "value"; 11 | 12 | // Act 13 | Action action = () => value.Throw().IfLongerThan(2); 14 | 15 | // Assert 16 | action.Should() 17 | .ThrowExactly() 18 | .WithMessage($"String should not be longer than 2 characters. (Parameter '{nameof(value)}')"); 19 | } 20 | 21 | [TestMethod] 22 | public void ThrowIfLongerThan_WhenNotLongerThan_ShouldNotThrow() 23 | { 24 | // Arrange 25 | string value = "value"; 26 | 27 | // Act 28 | Action action = () => value.Throw().IfLongerThan(100); 29 | 30 | // Assert 31 | action.Should().NotThrow(); 32 | } 33 | 34 | [TestMethod] 35 | public void ThrowIfShorterThan_WhenShorterThan_ShouldThrow() 36 | { 37 | // Arrange 38 | string value = "value"; 39 | 40 | // Act 41 | Action action = () => value.Throw().IfShorterThan(100); 42 | 43 | // Assert 44 | action.Should() 45 | .ThrowExactly() 46 | .WithMessage($"String should not be shorter than 100 characters. (Parameter '{nameof(value)}')"); 47 | } 48 | 49 | [TestMethod] 50 | public void ThrowIfShorterThan_WhenNotShorterThan_ShouldNotThrow() 51 | { 52 | // Arrange 53 | string value = "value"; 54 | 55 | // Act 56 | Action action = () => value.Throw().IfShorterThan(2); 57 | 58 | // Assert 59 | action.Should().NotThrow(); 60 | } 61 | 62 | [TestMethod] 63 | public void ThrowIfLengthEquals_WhenLengthEquals_ShouldThrow() 64 | { 65 | // Arrange 66 | string value = "value"; 67 | 68 | // Act 69 | Action action = () => value.Throw().IfLengthEquals(5); 70 | 71 | // Assert 72 | action.Should() 73 | .ThrowExactly() 74 | .WithMessage($"String length should not be equal to 5. (Parameter '{nameof(value)}')"); 75 | } 76 | 77 | [TestMethod] 78 | public void ThrowIfLengthEquals_WhenLengthNotEquals_ShouldNotThrow() 79 | { 80 | // Arrange 81 | string value = "value"; 82 | 83 | // Act 84 | Action action = () => value.Throw().IfLengthEquals(100); 85 | 86 | // Assert 87 | action.Should().NotThrow(); 88 | } 89 | 90 | [TestMethod] 91 | public void ThrowIfLengthNotEquals_WhenLengthNotEquals_ShouldThrow() 92 | { 93 | // Arrange 94 | string value = "value"; 95 | 96 | // Act 97 | Action action = () => value.Throw().IfLengthNotEquals(100); 98 | 99 | // Assert 100 | action.Should() 101 | .ThrowExactly() 102 | .WithMessage($"String length should be equal to 100. (Parameter '{nameof(value)}')"); 103 | } 104 | 105 | [TestMethod] 106 | public void ThrowIfLengthNotEquals_WhenLengthEquals_ShouldNotThrow() 107 | { 108 | // Arrange 109 | string value = "value"; 110 | 111 | // Act 112 | Action action = () => value.Throw().IfLengthNotEquals(value.Length); 113 | 114 | // Assert 115 | action.Should().NotThrow(); 116 | } 117 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableExtensions/Strings/ValidatableExtensions.Strings.RegexTests.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace Throw.UnitTests.ValidatableExtensions.Strings; 4 | 5 | [TestClass] 6 | public class StringRegexTests 7 | { 8 | [DataTestMethod] 9 | [DataRow("Amichai", @"^[a-zA-Z]+$", RegexOptions.None)] 10 | [DataRow("123456789", @"^[0-9]+$", RegexOptions.None)] 11 | [DataRow("My NAME", @"\bname\b", RegexOptions.IgnoreCase)] 12 | public void ThrowIfMatches_WhenMatchesRegexPattern_ShouldThrow(string value, string regexPattern, RegexOptions regexOptions) 13 | { 14 | // Act 15 | Action action = () => value.Throw().IfMatches(regexPattern, regexOptions); 16 | 17 | // Assert 18 | action.Should() 19 | .ThrowExactly() 20 | .WithMessage($"String should not match RegEx pattern '{regexPattern}' (Parameter '{nameof(value)}')"); 21 | } 22 | 23 | [DataTestMethod] 24 | [DataRow("123456789", @"^[a-zA-Z]+$", RegexOptions.None)] 25 | [DataRow("Amichai", @"^[0-9]+$", RegexOptions.None)] 26 | [DataRow("My AGE", @"\bname\b", RegexOptions.IgnoreCase)] 27 | public void ThrowIfMatches_WhenMatchesRegexPattern_ShouldNotThrow(string value, string regexPattern, RegexOptions regexOptions) 28 | { 29 | // Act 30 | Action action = () => value.Throw().IfMatches(regexPattern, regexOptions); 31 | 32 | // Assert 33 | action.Should().NotThrow(); 34 | } 35 | 36 | [DataTestMethod] 37 | [DataRow("Amichai", @"^[a-zA-Z]+$", RegexOptions.None)] 38 | [DataRow("123456789", @"^[0-9]+$", RegexOptions.None)] 39 | [DataRow("My NAME", @"\bname\b", RegexOptions.IgnoreCase)] 40 | public void ThrowIfMatches_WhenMatchesRegex_ShouldThrow(string value, string regexPattern, RegexOptions regexOptions) 41 | { 42 | // Arrange 43 | var regex = new Regex(regexPattern, regexOptions); 44 | 45 | // Act 46 | Action action = () => value.Throw().IfMatches(regex); 47 | 48 | // Assert 49 | action.Should() 50 | .ThrowExactly() 51 | .WithMessage($"String should not match RegEx pattern '{regexPattern}' (Parameter '{nameof(value)}')"); 52 | } 53 | 54 | [DataTestMethod] 55 | [DataRow("123456789", @"^[a-zA-Z]+$", RegexOptions.None)] 56 | [DataRow("Amichai", @"^[0-9]+$", RegexOptions.None)] 57 | [DataRow("My AGE", @"\bname\b", RegexOptions.IgnoreCase)] 58 | public void ThrowIfMatches_WhenMatchesRegex_ShouldNotThrow(string value, string regexPattern, RegexOptions regexOptions) 59 | { 60 | // Arrange 61 | var regex = new Regex(regexPattern, regexOptions); 62 | 63 | // Act 64 | Action action = () => value.Throw().IfMatches(regex); 65 | 66 | // Assert 67 | action.Should().NotThrow(); 68 | } 69 | 70 | [DataTestMethod] 71 | [DataRow("123456789", @"^[a-zA-Z]+$", RegexOptions.None)] 72 | [DataRow("Amichai", @"^[0-9]+$", RegexOptions.None)] 73 | [DataRow("My AGE", @"\bname\b", RegexOptions.IgnoreCase)] 74 | public void ThrowIfNotMatches_WhenMatchesRegexPattern_ShouldThrow(string value, string regexPattern, RegexOptions regexOptions) 75 | { 76 | // Act 77 | Action action = () => value.Throw().IfNotMatches(regexPattern, regexOptions); 78 | 79 | // Assert 80 | action.Should() 81 | .ThrowExactly() 82 | .WithMessage($"String should match RegEx pattern '{regexPattern}' (Parameter '{nameof(value)}')"); 83 | } 84 | 85 | [DataTestMethod] 86 | [DataRow("Amichai", @"^[a-zA-Z]+$", RegexOptions.None)] 87 | [DataRow("123456789", @"^[0-9]+$", RegexOptions.None)] 88 | [DataRow("My NAME", @"\bname\b", RegexOptions.IgnoreCase)] 89 | public void ThrowIfNotMatches_WhenMatchesRegexPattern_ShouldNotThrow(string value, string regexPattern, RegexOptions regexOptions) 90 | { 91 | // Act 92 | Action action = () => value.Throw().IfNotMatches(regexPattern, regexOptions); 93 | 94 | // Assert 95 | action.Should().NotThrow(); 96 | } 97 | 98 | [DataTestMethod] 99 | [DataRow("123456789", @"^[a-zA-Z]+$", RegexOptions.None)] 100 | [DataRow("Amichai", @"^[0-9]+$", RegexOptions.None)] 101 | [DataRow("My AGE", @"\bname\b", RegexOptions.IgnoreCase)] 102 | public void ThrowIfNotMatches_WhenMatchesRegex_ShouldThrow(string value, string regexPattern, RegexOptions regexOptions) 103 | { 104 | // Arrange 105 | var regex = new Regex(regexPattern, regexOptions); 106 | 107 | // Act 108 | Action action = () => value.Throw().IfNotMatches(regex); 109 | 110 | // Assert 111 | action.Should() 112 | .ThrowExactly() 113 | .WithMessage($"String should match RegEx pattern '{regexPattern}' (Parameter '{nameof(value)}')"); 114 | } 115 | 116 | [DataTestMethod] 117 | [DataRow("Amichai", @"^[a-zA-Z]+$", RegexOptions.None)] 118 | [DataRow("123456789", @"^[0-9]+$", RegexOptions.None)] 119 | [DataRow("My NAME", @"\bname\b", RegexOptions.IgnoreCase)] 120 | public void ThrowIfNotMatches_WhenMatchesRegex_ShouldNowThrow(string value, string regexPattern, RegexOptions regexOptions) 121 | { 122 | // Arrange 123 | var regex = new Regex(regexPattern, regexOptions); 124 | 125 | // Act 126 | Action action = () => value.Throw().IfNotMatches(regex); 127 | 128 | // Assert 129 | action.Should().NotThrow(); 130 | } 131 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableExtensions/ValidatableExtensions.BooleanPropertiesTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.ValidatableExtensions; 2 | 3 | [TestClass] 4 | public class BooleanPropertiesTests 5 | { 6 | [TestMethod] 7 | public void ThrowIfPropertyTrue_WhenPropertyIsTrue_ShouldThrow() 8 | { 9 | // Arrange 10 | var person = new { Id = 1 }; 11 | 12 | // Act 13 | Action action = () => person.Throw().IfTrue(p => p.Id == 1); 14 | 15 | // Assert 16 | action.Should() 17 | .ThrowExactly() 18 | .WithMessage($"Value should not meet condition (condition: 'p => p.Id == 1'). (Parameter '{nameof(person)}')"); 19 | } 20 | 21 | [TestMethod] 22 | public void ThrowIfPropertyTrue_WhenPropertyIsFalse_ShouldNotThrow() 23 | { 24 | // Arrange 25 | var person = new { Id = 1 }; 26 | 27 | // Act 28 | Action action = () => person.Throw().IfTrue(p => p.Id == 2); 29 | 30 | // Assert 31 | action.Should().NotThrow(); 32 | } 33 | 34 | [TestMethod] 35 | public void ThrowIfPropertyFalse_WhenPropertyIsFalse_ShouldThrow() 36 | { 37 | // Arrange 38 | var person = new { Id = 1 }; 39 | 40 | // Act 41 | Action action = () => person.Throw().IfFalse(p => p.Id == 2); 42 | 43 | // Assert 44 | action.Should() 45 | .ThrowExactly() 46 | .WithMessage($"Value should meet condition (condition: 'p => p.Id == 2'). (Parameter '{nameof(person)}')"); 47 | } 48 | 49 | [TestMethod] 50 | public void ThrowIfPropertyFalse_WhenPropertyIsTrue_ShouldNotThrow() 51 | { 52 | // Arrange 53 | var person = new { Id = 1 }; 54 | 55 | // Act 56 | Action action = () => person.Throw().IfFalse(p => p.Id == 1); 57 | 58 | // Assert 59 | action.Should().NotThrow(); 60 | } 61 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableExtensions/ValidatableExtensions.BooleansTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.ValidatableExtensions; 2 | 3 | [TestClass] 4 | public class BooleansTests 5 | { 6 | [TestMethod] 7 | public void ThrowIfTrue_WhenValueIsTrue_ShouldThrow() 8 | { 9 | // Arrange 10 | bool value = true; 11 | 12 | // Act 13 | Action action = () => value.Throw().IfTrue(); 14 | 15 | // Assert 16 | action.Should().ThrowExactly().WithMessage($"Value should not be true. (Parameter '{nameof(value)}')"); 17 | } 18 | 19 | [TestMethod] 20 | public void ThrowIfTrue_WhenValueIsFalse_ShouldNotThrow() 21 | { 22 | // Arrange 23 | bool value = false; 24 | 25 | // Act 26 | Action action = () => value.Throw().IfTrue(); 27 | 28 | // Assert 29 | action.Should().NotThrow(); 30 | } 31 | 32 | [TestMethod] 33 | public void ThrowIfFalse_WhenValueIsTrue_ShouldNotThrow() 34 | { 35 | // Arrange 36 | bool value = true; 37 | 38 | // Act 39 | Action action = () => value.Throw().IfFalse(); 40 | 41 | // Assert 42 | action.Should().NotThrow(); 43 | } 44 | 45 | [TestMethod] 46 | public void ThrowIfFalse_WhenValueIsFalse_ShouldThrow() 47 | { 48 | // Arrange 49 | bool value = false; 50 | 51 | // Act 52 | Action action = () => value.Throw().IfFalse(); 53 | 54 | // Assert 55 | action.Should().ThrowExactly().WithMessage($"Value should be true. (Parameter '{nameof(value)}')"); 56 | } 57 | 58 | [TestMethod] 59 | public void ThrowIfConditionTrue_WhenConditionIsTrue_ShouldThrow() 60 | { 61 | // Arrange 62 | var value = "value"; 63 | 64 | // Act 65 | Action action = () => value.Throw().IfTrue(value.Length > 0); 66 | 67 | // Assert 68 | action.Should() 69 | .ThrowExactly() 70 | .WithMessage($"Value should not meet condition (condition: 'value.Length > 0'). (Parameter '{nameof(value)}')"); 71 | } 72 | 73 | [TestMethod] 74 | public void ThrowIfConditionTrue_WhenConditionIsFalse_ShouldNotThrow() 75 | { 76 | // Arrange 77 | var value = "value"; 78 | 79 | // Act 80 | Action action = () => value.Throw().IfTrue(value.Length == 0); 81 | 82 | // Assert 83 | action.Should().NotThrow(); 84 | } 85 | 86 | [TestMethod] 87 | public void ThrowIfConditionFalse_WhenConditionIsTrue_ShouldNotThrow() 88 | { 89 | // Arrange 90 | var value = "value"; 91 | 92 | // Act 93 | Action action = () => value.Throw().IfFalse(value.Length > 0); 94 | 95 | // Assert 96 | action.Should().NotThrow(); 97 | } 98 | 99 | [TestMethod] 100 | public void ThrowIfConditionFalse_WhenConditionIsFalse_ShouldThrow() 101 | { 102 | // Arrange 103 | var value = "value"; 104 | 105 | // Act 106 | Action action = () => value.Throw().IfFalse(value.Length == 0); 107 | 108 | // Assert 109 | action.Should() 110 | .ThrowExactly() 111 | .WithMessage($"Value should meet condition (condition: 'value.Length == 0'). (Parameter '{nameof(value)}')"); 112 | } 113 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableExtensions/ValidatableExtensions.CollectionsTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.ValidatableExtensions; 2 | 3 | [TestClass] 4 | public class CollectionsTests 5 | { 6 | [TestMethod] 7 | public void ThrowIfCollectionEmpty_WhenCollectionIsEmpty_ShouldThrow() 8 | { 9 | // Arrange 10 | var collection = Array.Empty(); 11 | 12 | // Act 13 | Action action = () => collection.Throw().IfEmpty(); 14 | 15 | // Assert 16 | action.Should().ThrowExactly() 17 | .WithMessage($"Collection should not be empty. (Parameter '{nameof(collection)}')"); 18 | } 19 | 20 | [TestMethod] 21 | public void ThrowIfCollectionEmpty_WhenCollectionIsNotEmpty_ShouldNotThrow() 22 | { 23 | // Arrange 24 | var collection = new[] { 1 }; 25 | 26 | // Act 27 | Action action = () => collection.Throw().IfEmpty(); 28 | 29 | // Assert 30 | action.Should().NotThrow(); 31 | } 32 | 33 | [TestMethod] 34 | public void ThrowIfCollectionNotEmpty_WhenCollectionIsNotEmpty_ShouldThrow() 35 | { 36 | // Arrange 37 | var collection = new[] { 1 }; 38 | 39 | // Act 40 | Action action = () => collection.Throw().IfNotEmpty(); 41 | 42 | // Assert 43 | action.Should().ThrowExactly() 44 | .WithMessage($"Collection should be empty. (Parameter '{nameof(collection)}')"); 45 | } 46 | 47 | [TestMethod] 48 | public void ThrowIfCollectionNotEmpty_WhenCollectionIsEmpty_ShouldNotThrow() 49 | { 50 | // Arrange 51 | var collection = Array.Empty(); 52 | 53 | // Act 54 | Action action = () => collection.Throw().IfNotEmpty(); 55 | 56 | // Assert 57 | action.Should().NotThrow(); 58 | } 59 | 60 | [TestMethod] 61 | public void ThrowIfCollectionCountEquals_WhenCollectionCountEquals_ShouldThrow() 62 | { 63 | // Arrange 64 | var collection = new[] { 1 }; 65 | 66 | // Act 67 | Action action = () => collection.Throw().IfCountEquals(1); 68 | 69 | // Assert 70 | action.Should().ThrowExactly() 71 | .WithMessage($"Collection count should not be equal to 1. (Parameter '{nameof(collection)}')"); 72 | } 73 | 74 | [TestMethod] 75 | public void ThrowIfCollectionCountEquals_WhenCollectionCountNotEquals_ShouldNotThrow() 76 | { 77 | // Arrange 78 | var collection = new[] { 1 }; 79 | 80 | // Act 81 | Action action = () => collection.Throw().IfCountEquals(2); 82 | 83 | // Assert 84 | action.Should().NotThrow(); 85 | } 86 | 87 | [TestMethod] 88 | public void ThrowIfCollectionCountNotEquals_WhenCollectionCountNotEquals_ShouldThrow() 89 | { 90 | // Arrange 91 | var collection = new[] { 1 }; 92 | 93 | // Act 94 | Action action = () => collection.Throw().IfCountNotEquals(2); 95 | 96 | // Assert 97 | action.Should().ThrowExactly() 98 | .WithMessage($"Collection count should be equal to 2. (Parameter '{nameof(collection)}')"); 99 | } 100 | 101 | [TestMethod] 102 | public void ThrowIfCollectionCountNotEquals_WhenCollectionCountEquals_ShouldNotThrow() 103 | { 104 | // Arrange 105 | var collection = new[] { 1 }; 106 | 107 | // Act 108 | Action action = () => collection.Throw().IfCountNotEquals(1); 109 | 110 | // Assert 111 | action.Should().NotThrow(); 112 | } 113 | 114 | [TestMethod] 115 | public void ThrowIfCollectionCountGreaterThan_WhenCollectionCountGreaterThan_ShouldThrow() 116 | { 117 | // Arrange 118 | var collection = new[] { 1 }; 119 | 120 | // Act 121 | Action action = () => collection.Throw().IfCountGreaterThan(0); 122 | 123 | // Assert 124 | action.Should().ThrowExactly() 125 | .WithMessage($"Collection count should not be greater than 0. (Parameter '{nameof(collection)}')"); 126 | } 127 | 128 | [TestMethod] 129 | public void ThrowIfCollectionCountGreaterThan_WhenCollectionCountNotGreaterThan_ShouldNotThrow() 130 | { 131 | // Arrange 132 | var collection = new[] { 1 }; 133 | 134 | // Act 135 | Action action = () => collection.Throw().IfCountGreaterThan(2); 136 | 137 | // Assert 138 | action.Should().NotThrow(); 139 | } 140 | 141 | [TestMethod] 142 | public void ThrowIfCollectionCountGreaterThan_WhenCollectionCountEquals_ShouldNotThrow() 143 | { 144 | // Arrange 145 | var collection = new[] { 1 }; 146 | 147 | // Act 148 | Action action = () => collection.Throw().IfCountGreaterThan(1); 149 | 150 | // Assert 151 | action.Should().NotThrow(); 152 | } 153 | 154 | [TestMethod] 155 | public void ThrowIfCollectionCountLessThan_WhenCollectionCountLessThan_ShouldThrow() 156 | { 157 | // Arrange 158 | var collection = new[] { 1 }; 159 | 160 | // Act 161 | Action action = () => collection.Throw().IfCountLessThan(2); 162 | 163 | // Assert 164 | action.Should().ThrowExactly() 165 | .WithMessage($"Collection count should not be less than 2. (Parameter '{nameof(collection)}')"); 166 | } 167 | 168 | [TestMethod] 169 | public void ThrowIfCollectionCountLessThan_WhenCollectionCountNotLessThan_ShouldNotThrow() 170 | { 171 | // Arrange 172 | var collection = new[] { 1 }; 173 | 174 | // Act 175 | Action action = () => collection.Throw().IfCountLessThan(0); 176 | 177 | // Assert 178 | action.Should().NotThrow(); 179 | } 180 | 181 | [TestMethod] 182 | public void ThrowIfCollectionCountLessThan_WhenCollectionCountEquals_ShouldNotThrow() 183 | { 184 | // Arrange 185 | var collection = new[] { 1 }; 186 | 187 | // Act 188 | Action action = () => collection.Throw().IfCountLessThan(1); 189 | 190 | // Assert 191 | action.Should().NotThrow(); 192 | } 193 | 194 | [TestMethod] 195 | public void ThrowIfCollectionHasNullElements_WhenCollectionHasNullElements_ShouldThrow() 196 | { 197 | // Arrange 198 | var collection = new[] { "hey", null }; 199 | 200 | // Act 201 | Action action = () => collection.Throw().IfHasNullElements(); 202 | 203 | // Assert 204 | action.Should().ThrowExactly() 205 | .WithMessage($"Collection should not have null elements. (Parameter '{nameof(collection)}')"); 206 | } 207 | 208 | [TestMethod] 209 | public void ThrowIfCollectionHasNullElements_WhenCollectionHasNoNullElements_ShouldNotThrow() 210 | { 211 | // Arrange 212 | var collection = new[] { "hey", "ho" }; 213 | 214 | // Act 215 | Action action = () => collection.Throw().IfHasNullElements(); 216 | 217 | // Assert 218 | action.Should().NotThrow(); 219 | } 220 | 221 | [TestMethod] 222 | public void ThrowIfCollectionContains_WhenCollectionContainsElement_ShouldThrow() 223 | { 224 | // Arrange 225 | var collection = new[] { "hey", null, "ho" }; 226 | var collection2 = new[] { 1, 2 }; 227 | 228 | // Act 229 | Action action = () => collection.Throw().IfContains("ho"); 230 | Action action2 = () => collection2.Throw().IfContains(1); 231 | 232 | // Assert 233 | action.Should().ThrowExactly() 234 | .WithMessage($"Collection should not contain element. (Parameter '{nameof(collection)}')"); 235 | action2.Should().ThrowExactly() 236 | .WithMessage($"Collection should not contain element. (Parameter '{nameof(collection2)}')"); 237 | } 238 | 239 | [TestMethod] 240 | public void ThrowIfCollectionContains_WhenCollectionNotContainsElement_ShouldNotThrow() 241 | { 242 | // Arrange 243 | var collection = new[] { "hey", null, "ho" }; 244 | var collection2 = new[] { 1, 2 }; 245 | 246 | // Act 247 | Action action = () => collection.Throw().IfContains("ho1"); 248 | Action action2 = () => collection2.Throw().IfContains(3); 249 | 250 | // Assert 251 | action.Should().NotThrow(); 252 | action2.Should().NotThrow(); 253 | } 254 | 255 | [TestMethod] 256 | public void ThrowIfCollectionNotContains_WhenCollectionNotContainsElement_ShouldThrow() 257 | { 258 | // Arrange 259 | var collection = new[] { "hey", null, "ho" }; 260 | var collection2 = new[] { 1, 2 }; 261 | 262 | // Act 263 | Action action = () => collection.Throw().IfNotContains("ho1"); 264 | Action action2 = () => collection2.Throw().IfNotContains(3); 265 | 266 | // Assert 267 | action.Should().ThrowExactly() 268 | .WithMessage($"Collection should contain element. (Parameter '{nameof(collection)}')"); 269 | action2.Should().ThrowExactly() 270 | .WithMessage($"Collection should contain element. (Parameter '{nameof(collection2)}')"); 271 | } 272 | 273 | [TestMethod] 274 | public void ThrowIfCollectionNotContains_WhenCollectionContainsElement_ShouldNotThrow() 275 | { 276 | // Arrange 277 | var collection = new[] { "hey", null, "ho" }; 278 | var collection2 = new[] { 1, 2 }; 279 | 280 | // Act 281 | Action action = () => collection.Throw().IfNotContains("hey"); 282 | Action action2 = () => collection2.Throw().IfNotContains(1); 283 | 284 | // Assert 285 | action.Should().NotThrow(); 286 | action2.Should().NotThrow(); 287 | } 288 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableExtensions/ValidatableExtensions.ConditionalCompilationTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.ValidatableExtensions; 2 | 3 | [TestClass] 4 | public class ConditionalCompilationTests 5 | { 6 | [TestMethod] 7 | public void ThrowOnlyInDebug_WhenPresent_ShouldThrowOnlyInDebugBuild() 8 | { 9 | // Arrange 10 | var person = new { BirthDate = DateTime.UtcNow }; 11 | 12 | // Act 13 | Action action = () => person.Throw().IfUtc(p => p.BirthDate).OnlyInDebug(); 14 | 15 | // Assert 16 | #if DEBUG 17 | action.Should() 18 | .ThrowExactly() 19 | .WithMessage($"Value should not be Utc. (Parameter '{nameof(person)}: p => p.BirthDate')"); 20 | #else 21 | action.Should().NotThrow(); 22 | #endif 23 | } 24 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableExtensions/ValidatableExtensions.DateTimePropertiesTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.ValidatableExtensions; 2 | 3 | [TestClass] 4 | public class DateTimePropertiesTests 5 | { 6 | [TestMethod] 7 | public void ThrowIfDateTimePropertyUtc_WhenValueIsUtc_ShouldThrow() 8 | { 9 | // Arrange 10 | var person = new { BirthDate = DateTime.UtcNow }; 11 | 12 | // Act 13 | Action action = () => person.Throw().IfUtc(p => p.BirthDate); 14 | 15 | // Assert 16 | action.Should() 17 | .ThrowExactly() 18 | .WithMessage($"Value should not be Utc. (Parameter '{nameof(person)}: p => p.BirthDate')"); 19 | } 20 | 21 | [TestMethod] 22 | public void ThrowIfDateTimePropertyUtc_WhenValueIsNotUtc_ShouldNotThrow() 23 | { 24 | // Arrange 25 | var person = new { BirthDate = DateTime.Now }; 26 | 27 | // Act 28 | Action action = () => person.Throw().IfUtc(p => p.BirthDate); 29 | 30 | // Assert 31 | action.Should().NotThrow(); 32 | } 33 | 34 | [TestMethod] 35 | public void ThrowIfDateTimePropertyNotUtc_WhenValueIsNotUtc_ShouldThrow() 36 | { 37 | // Arrange 38 | var person = new { BirthDate = DateTime.Now }; 39 | 40 | // Act 41 | Action action = () => person.Throw().IfNotUtc(p => p.BirthDate); 42 | 43 | // Assert 44 | action.Should() 45 | .ThrowExactly() 46 | .WithMessage($"Value should be Utc. (Parameter '{nameof(person)}: p => p.BirthDate')"); 47 | } 48 | 49 | [TestMethod] 50 | public void ThrowIfDateTimePropertyNotUtc_WhenValueIsUtc_ShouldNotThrow() 51 | { 52 | // Arrange 53 | var person = new { BirthDate = DateTime.UtcNow }; 54 | 55 | // Act 56 | Action action = () => person.Throw().IfNotUtc(p => p.BirthDate); 57 | 58 | // Assert 59 | action.Should().NotThrow(); 60 | } 61 | 62 | [TestMethod] 63 | public void ThrowIfDateTimeKindPropertyUtc_WhenValueIsUtc_ShouldThrow() 64 | { 65 | // Arrange 66 | var person = new { BirthDate = DateTime.UtcNow }; 67 | 68 | // Act 69 | Action action = () => person.Throw().IfDateTimeKind(p => p.BirthDate, DateTimeKind.Utc); 70 | 71 | // Assert 72 | action.Should() 73 | .ThrowExactly() 74 | .WithMessage($"Value should not be Utc. (Parameter '{nameof(person)}: p => p.BirthDate')"); 75 | } 76 | 77 | [TestMethod] 78 | public void ThrowIfDateTimeKindPropertyUtc_WhenValueIsNotUtc_ShouldNotThrow() 79 | { 80 | // Arrange 81 | var person = new { BirthDate = DateTime.Now }; 82 | 83 | // Act 84 | Action action = () => person.Throw().IfDateTimeKind(p => p.BirthDate, DateTimeKind.Utc); 85 | 86 | // Assert 87 | action.Should().NotThrow(); 88 | } 89 | 90 | [TestMethod] 91 | public void ThrowIfDateTimeKindPropertyNotUtc_WhenValueIsNotUtc_ShouldThrow() 92 | { 93 | // Arrange 94 | var person = new { BirthDate = DateTime.Now }; 95 | 96 | // Act 97 | Action action = () => person.Throw().IfDateTimeKindNot(p => p.BirthDate, DateTimeKind.Utc); 98 | 99 | // Assert 100 | action.Should() 101 | .ThrowExactly() 102 | .WithMessage($"Value should be Utc. (Parameter '{nameof(person)}: p => p.BirthDate')"); 103 | } 104 | 105 | [TestMethod] 106 | public void ThrowIfDateTimeKindPropertyNotUtc_WhenValueIsUtc_ShouldNotThrow() 107 | { 108 | // Arrange 109 | var person = new { BirthDate = DateTime.UtcNow }; 110 | 111 | // Act 112 | Action action = () => person.Throw().IfDateTimeKindNot(p => p.BirthDate, DateTimeKind.Utc); 113 | 114 | // Assert 115 | action.Should().NotThrow(); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableExtensions/ValidatableExtensions.DateTimesTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.ValidatableExtensions; 2 | 3 | [TestClass] 4 | public class DateTimesTests 5 | { 6 | [TestMethod] 7 | public void ThrowIfUtc_WhenDateTimeIsUtc_ShouldThrow() 8 | { 9 | // Arrange 10 | var dateTime = DateTime.UtcNow; 11 | 12 | // Act 13 | Action action = () => dateTime.Throw().IfUtc(); 14 | 15 | // Assert 16 | action.Should().ThrowExactly().WithMessage($"Value should not be Utc. (Parameter '{nameof(dateTime)}')"); 17 | } 18 | 19 | [TestMethod] 20 | public void ThrowIfUtc_WhenDateTimeIsNotUtc_ShouldNotThrow() 21 | { 22 | // Arrange 23 | var dateTime = DateTime.Now; 24 | 25 | // Act 26 | Action action = () => dateTime.Throw().IfUtc(); 27 | 28 | // Assert 29 | action.Should().NotThrow(); 30 | } 31 | 32 | [TestMethod] 33 | public void ThrowIfNotUtc_WhenDateTimeIsNotUtc_ShouldThrow() 34 | { 35 | // Arrange 36 | var dateTime = DateTime.Now; 37 | 38 | // Act 39 | Action action = () => dateTime.Throw().IfNotUtc(); 40 | 41 | // Assert 42 | action.Should().ThrowExactly().WithMessage($"Value should be Utc. (Parameter '{nameof(dateTime)}')"); 43 | } 44 | 45 | [TestMethod] 46 | public void ThrowIfNotUtc_WhenDateTimeIsUtc_ShouldNotThrow() 47 | { 48 | // Arrange 49 | var dateTime = DateTime.UtcNow; 50 | 51 | // Act 52 | Action action = () => dateTime.Throw().IfNotUtc(); 53 | 54 | // Assert 55 | action.Should().NotThrow(); 56 | } 57 | 58 | [TestMethod] 59 | public void ThrowIfDateTimeKind_WhenDateTimeKindEquals_ShouldThrow() 60 | { 61 | // Arrange 62 | var dateTime = DateTime.UtcNow; 63 | 64 | // Act 65 | Action action = () => dateTime.Throw().IfDateTimeKind(DateTimeKind.Utc); 66 | 67 | // Assert 68 | action.Should().ThrowExactly().WithMessage($"Value should not be Utc. (Parameter '{nameof(dateTime)}')"); 69 | } 70 | 71 | [TestMethod] 72 | public void ThrowIfDateTimeKind_WhenDateTimeKindNotEquals_ShouldNotThrow() 73 | { 74 | // Arrange 75 | var dateTime = DateTime.Now; 76 | 77 | // Act 78 | Action action = () => dateTime.Throw().IfDateTimeKind(DateTimeKind.Utc); 79 | 80 | // Assert 81 | action.Should().NotThrow(); 82 | } 83 | 84 | [TestMethod] 85 | public void ThrowIfDateTimeKindNot_WhenDateTimeKindEquals_ShouldNotThrow() 86 | { 87 | // Arrange 88 | var dateTime = DateTime.UtcNow; 89 | 90 | // Act 91 | Action action = () => dateTime.Throw().IfDateTimeKindNot(DateTimeKind.Utc); 92 | 93 | // Assert 94 | action.Should().NotThrow(); 95 | } 96 | 97 | [TestMethod] 98 | public void ThrowIfDateTimeKindNot_WhenDateTimeKindNotEquals_ShouldThrow() 99 | { 100 | // Arrange 101 | var dateTime = DateTime.Now; 102 | 103 | // Act 104 | Action action = () => dateTime.Throw().IfDateTimeKindNot(DateTimeKind.Utc); 105 | 106 | // Assert 107 | action.Should().ThrowExactly().WithMessage($"Value should be Utc. (Parameter '{nameof(dateTime)}')"); 108 | } 109 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableExtensions/ValidatableExtensions.EnumPropertiesTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.ValidatableExtensions; 2 | 3 | [TestClass] 4 | public class EnumPropertiesTests 5 | { 6 | [TestMethod] 7 | public void ThrowIfEnumPropertyOutOfRange_WhenValueIsOutOfRange_ShouldThrow() 8 | { 9 | // Arrange 10 | var person = new { PersonType = (PersonType)10 }; 11 | 12 | // Act 13 | Action action = () => person.Throw().IfOutOfRange(p => p.PersonType); 14 | 15 | // Assert 16 | action.Should() 17 | .ThrowExactly() 18 | .WithMessage($"Value should be defined in enum. (Parameter '{nameof(person)}: p => p.PersonType')\nActual value was {person.PersonType}."); 19 | } 20 | 21 | [TestMethod] 22 | public void ThrowIfEnumPropertyOutOfRange_WhenValueIsInRange_ShouldNotThrow() 23 | { 24 | // Arrange 25 | var person = new { PersonType = PersonType.NotFunny }; 26 | 27 | // Act 28 | Action action = () => person.Throw().IfOutOfRange(p => p.PersonType); 29 | 30 | // Assert 31 | action.Should().NotThrow(); 32 | } 33 | 34 | private enum PersonType 35 | { 36 | Funny, 37 | NotFunny, 38 | } 39 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableExtensions/ValidatableExtensions.EnumsTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.ValidatableExtensions; 2 | 3 | [TestClass] 4 | public class EnumsTests 5 | { 6 | [TestMethod] 7 | public void ThrowIfEnumOutOfRange_WhenValueIsOutOfRange_ShouldThrow() 8 | { 9 | // Arrange 10 | TestEnum value = (TestEnum)4; 11 | 12 | // Act 13 | Action action = () => value.Throw().IfOutOfRange(); 14 | 15 | // Assert 16 | action.Should() 17 | .ThrowExactly() 18 | .WithMessage($"Value should be defined in enum. (Parameter '{nameof(value)}')\nActual value was {value}."); 19 | } 20 | 21 | [TestMethod] 22 | public void ThrowIfEnumOutOfRange_WhenValueIsInRange_ShouldNotThrow() 23 | { 24 | // Arrange 25 | TestEnum value = TestEnum.Value1; 26 | 27 | // Act 28 | Action action = () => value.Throw().IfOutOfRange(); 29 | 30 | // Assert 31 | action.Should().NotThrow(); 32 | } 33 | 34 | private enum TestEnum 35 | { 36 | Value1, 37 | Value2, 38 | } 39 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableExtensions/ValidatableExtensions.EqualitiesTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.ValidatableExtensions; 2 | 3 | [TestClass] 4 | public class EqualitiesTests 5 | { 6 | [TestMethod] 7 | public void ThrowIfDefault_WhenValueIsDefault_ShouldThrow() 8 | { 9 | // Arrange 10 | DateTime value = default; 11 | 12 | // Act 13 | Action action = () => value.Throw().IfDefault(); 14 | 15 | // Assert 16 | action.Should() 17 | .ThrowExactly() 18 | .WithMessage($"Value should not be default. (Parameter '{nameof(value)}')"); 19 | } 20 | 21 | [TestMethod] 22 | public void ThrowIfDefault_WhenValueIsNotDefault_ShouldNotThrow() 23 | { 24 | // Arrange 25 | DateTime value = DateTime.Now; 26 | 27 | // Act 28 | Action action = () => value.Throw().IfDefault(); 29 | 30 | // Assert 31 | action.Should().NotThrow(); 32 | } 33 | 34 | [TestMethod] 35 | public void ThrowIfNotDefault_WhenValueIsNotDefault_ShouldThrow() 36 | { 37 | // Arrange 38 | DateTime value = DateTime.Now; 39 | 40 | // Act 41 | Action action = () => value.Throw().IfNotDefault(); 42 | 43 | // Assert 44 | action.Should() 45 | .ThrowExactly() 46 | .WithMessage($"Value should be default. (Parameter '{nameof(value)}')"); 47 | } 48 | 49 | [TestMethod] 50 | public void ThrowIfNotDefault_WhenValueIsDefault_ShouldNotThrow() 51 | { 52 | // Arrange 53 | DateTime value = default; 54 | 55 | // Act 56 | Action action = () => value.Throw().IfNotDefault(); 57 | 58 | // Assert 59 | action.Should().NotThrow(); 60 | } 61 | 62 | [TestMethod] 63 | public void ThrowIfEquals_WhenValueEquals_ShouldThrow() 64 | { 65 | // Arrange 66 | int value = 5; 67 | 68 | // Act 69 | Action action = () => value.Throw().IfEquals(5); 70 | 71 | // Assert 72 | action.Should() 73 | .ThrowExactly() 74 | .WithMessage($"Value should not be equal to 5. (Parameter '{nameof(value)}')"); 75 | } 76 | 77 | [TestMethod] 78 | public void ThrowIfEquals_WhenValueIsNotEqual_ShouldNotThrow() 79 | { 80 | // Arrange 81 | int value = 5; 82 | 83 | // Act 84 | Action action = () => value.Throw().IfEquals(6); 85 | 86 | // Assert 87 | action.Should().NotThrow(); 88 | } 89 | 90 | [TestMethod] 91 | public void ThrowIfNotEquals_WhenNotEquals_ShouldThrow() 92 | { 93 | // Arrange 94 | int value = 5; 95 | 96 | // Act 97 | Action action = () => value.Throw().IfNotEquals(6); 98 | 99 | // Assert 100 | action.Should() 101 | .ThrowExactly() 102 | .WithMessage($"Value should be equal to 6. (Parameter '{nameof(value)}')"); 103 | } 104 | 105 | [TestMethod] 106 | public void ThrowIfNotEquals_WhenEquals_ShouldNotThrow() 107 | { 108 | // Arrange 109 | int value = 5; 110 | 111 | // Act 112 | Action action = () => value.Throw().IfNotEquals(5); 113 | 114 | // Assert 115 | action.Should().NotThrow(); 116 | } 117 | 118 | [TestMethod] 119 | public void ThrowIfEquals_WhenObjectReferenceEquals_ShouldThrow() 120 | { 121 | // Arrange 122 | var value1 = new object(); 123 | var value2 = value1; 124 | 125 | // Act 126 | Action action = () => value1.Throw().IfEquals(value2); 127 | 128 | // Assert 129 | action.Should() 130 | .ThrowExactly() 131 | .WithMessage($"Value should not be equal to {value2}. (Parameter '{nameof(value1)}')"); 132 | } 133 | 134 | [TestMethod] 135 | public void ThrowIfEquals_WhenObjectReferenceIsNotEqual_ShouldNotThrow() 136 | { 137 | // Arrange 138 | var value1 = new object(); 139 | var value2 = new object(); 140 | 141 | // Act 142 | Action action = () => value1.Throw().IfEquals(value2); 143 | 144 | // Assert 145 | action.Should().NotThrow(); 146 | } 147 | 148 | [TestMethod] 149 | public void ThrowIfNotEquals_WhenObjectReferenceIsNotEqual_ShouldThrow() 150 | { 151 | // Arrange 152 | var value1 = new object(); 153 | var value2 = new object(); 154 | 155 | // Act 156 | Action action = () => value1.Throw().IfNotEquals(value2); 157 | 158 | // Assert 159 | action.Should() 160 | .ThrowExactly() 161 | .WithMessage($"Value should be equal to {value2}. (Parameter '{nameof(value1)}')"); 162 | } 163 | 164 | [TestMethod] 165 | public void ThrowIfNotEquals_WhenObjectReferenceEquals_ShouldNotThrow() 166 | { 167 | // Arrange 168 | var value1 = new object(); 169 | var value2 = value1; 170 | 171 | // Act 172 | Action action = () => value1.Throw().IfNotEquals(value2); 173 | 174 | // Assert 175 | action.Should().NotThrow(); 176 | } 177 | 178 | [TestMethod] 179 | public void ThrowIfEquals_WhenOverrideEqualsTypeEquals_ShouldThrow() 180 | { 181 | // Arrange 182 | var value1 = new OverrideEqualsType(1); 183 | var value2 = new OverrideEqualsType(1); 184 | 185 | // Act 186 | Action action = () => value1.Throw().IfEquals(value2); 187 | 188 | // Assert 189 | action.Should() 190 | .ThrowExactly() 191 | .WithMessage($"Value should not be equal to {value2}. (Parameter '{nameof(value1)}')"); 192 | } 193 | 194 | [TestMethod] 195 | public void ThrowIfEquals_WhenOverridequalsTypeIsNotEqual_ShouldNotThrow() 196 | { 197 | // Arrange 198 | var value1 = new OverrideEqualsType(1); 199 | var value2 = new OverrideEqualsType(2); 200 | 201 | // Act 202 | Action action = () => value1.Throw().IfEquals(value2); 203 | 204 | // Assert 205 | action.Should().NotThrow(); 206 | } 207 | 208 | [TestMethod] 209 | public void ThrowIfNotEquals_WhenOverridequalsTypeIsNotEqual_ShouldThrow() 210 | { 211 | // Arrange 212 | var value1 = new OverrideEqualsType(1); 213 | var value2 = new OverrideEqualsType(2); 214 | 215 | // Act 216 | Action action = () => value1.Throw().IfNotEquals(value2); 217 | 218 | // Assert 219 | action.Should() 220 | .ThrowExactly() 221 | .WithMessage($"Value should be equal to {value2}. (Parameter '{nameof(value1)}')"); 222 | } 223 | 224 | [TestMethod] 225 | public void ThrowIfNotEquals_WhenOverridequalsTypeEquals_ShouldNotThrow() 226 | { 227 | // Arrange 228 | var value1 = new OverrideEqualsType(1); 229 | var value2 = new OverrideEqualsType(1); 230 | 231 | // Act 232 | Action action = () => value1.Throw().IfNotEquals(value2); 233 | 234 | // Assert 235 | action.Should().NotThrow(); 236 | } 237 | 238 | private class OverrideEqualsType 239 | { 240 | public OverrideEqualsType(int id) => this.Id = id; 241 | 242 | public int Id { get; } 243 | 244 | public override bool Equals(object? obj) 245 | { 246 | if (obj is not OverrideEqualsType other) 247 | { 248 | return false; 249 | } 250 | 251 | return this.Id == other.Id; 252 | } 253 | 254 | public override int GetHashCode() => this.Id.GetHashCode(); 255 | } 256 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableExtensions/ValidatableExtensions.EqualityPropertiesTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.ValidatableExtensions; 2 | 3 | [TestClass] 4 | public class EqualityPropertiesTests 5 | { 6 | [TestMethod] 7 | public void ThrowIfPropertyIsNull_WhenPropertyIsNull_ShouldThrow() 8 | { 9 | // Arrange 10 | var value = new { Property = null as string }; 11 | 12 | // Act 13 | Action action = () => value.Throw().IfNull(v => v.Property); 14 | 15 | // Assert 16 | action.Should() 17 | .ThrowExactly() 18 | .WithMessage($"Value cannot be null. (Parameter '{nameof(value)}: v => v.Property')"); 19 | } 20 | 21 | [TestMethod] 22 | public void ThrowIfPropertyIsNull_WhenPropertyIsNotNull_ShouldNotThrow() 23 | { 24 | // Arrange 25 | var value = new { Property = "value" }; 26 | 27 | // Act 28 | Action action = () => value.Throw().IfNull(v => v.Property); 29 | 30 | // Assert 31 | action.Should().NotThrow(); 32 | } 33 | 34 | [TestMethod] 35 | public void ThrowIfPropertyIsNotNull_WhenPropertyIsNotNull_ShouldThrow() 36 | { 37 | // Arrange 38 | var value = new { Property = "value" }; 39 | 40 | // Act 41 | Action action = () => value.Throw().IfNotNull(v => v.Property); 42 | 43 | // Assert 44 | action.Should() 45 | .ThrowExactly() 46 | .WithMessage($"Value should be null. (Parameter '{nameof(value)}: v => v.Property')"); 47 | } 48 | 49 | [TestMethod] 50 | public void ThrowIfPropertyIsNotNull_WhenPropertyIsNull_ShouldThrow() 51 | { 52 | // Arrange 53 | var value = new { Property = default(string) }; 54 | 55 | // Act 56 | Action action = () => value.Throw().IfNotNull(v => v.Property); 57 | 58 | // Assert 59 | action.Should().NotThrow(); 60 | } 61 | 62 | [TestMethod] 63 | public void ThrowIfPropertyIsDefault_WhenValueIsDefault_ShouldThrow() 64 | { 65 | // Arrange 66 | var person = new { BirthDate = default(DateTime) }; 67 | 68 | // Act 69 | Action action = () => person.Throw().IfDefault(p => p.BirthDate); 70 | 71 | // Assert 72 | action.Should() 73 | .ThrowExactly() 74 | .WithMessage($"Value should not be default. (Parameter '{nameof(person)}: p => p.BirthDate')"); 75 | } 76 | 77 | [TestMethod] 78 | public void ThrowIfPropertyIsDefault_WhenValueIsNotDefault_ShouldNotThrow() 79 | { 80 | // Arrange 81 | var person = new { BirthDate = DateTime.Now }; 82 | 83 | // Act 84 | Action action = () => person.Throw().IfDefault(p => p.BirthDate); 85 | 86 | // Assert 87 | action.Should().NotThrow(); 88 | } 89 | 90 | [TestMethod] 91 | public void ThrowIfPropertyIsNotDefault_WhenValueIsNotDefault_ShouldThrow() 92 | { 93 | // Arrange 94 | var person = new { BirthDate = DateTime.Now }; 95 | 96 | // Act 97 | Action action = () => person.Throw().IfNotDefault(p => p.BirthDate); 98 | 99 | // Assert 100 | action.Should() 101 | .ThrowExactly() 102 | .WithMessage($"Value should be default. (Parameter '{nameof(person)}: p => p.BirthDate')"); 103 | } 104 | 105 | [TestMethod] 106 | public void ThrowIfPropertyIsNotDefault_WhenValueIsDefault_ShouldNotThrow() 107 | { 108 | // Arrange 109 | var person = new { BirthDate = default(DateTime) }; 110 | 111 | // Act 112 | Action action = () => person.Throw().IfNotDefault(p => p.BirthDate); 113 | 114 | // Assert 115 | action.Should().NotThrow(); 116 | } 117 | 118 | [TestMethod] 119 | public void ThrowIfPropertyEquals_WhenPropertyEquals_ShouldThrow() 120 | { 121 | // Arrange 122 | var value = new { Property = 5 }; 123 | 124 | // Act 125 | Action action = () => value.Throw().IfEquals(v => v.Property, 5); 126 | 127 | // Assert 128 | action.Should() 129 | .ThrowExactly() 130 | .WithMessage($"Value should not be equal to 5. (Parameter '{nameof(value)}: v => v.Property')"); 131 | } 132 | 133 | [TestMethod] 134 | public void ThrowIfPropertyEquals_WhenPropertyNotEquals_ShouldNotThrow() 135 | { 136 | // Arrange 137 | var value = new { Property = 5 }; 138 | 139 | // Act 140 | Action action = () => value.Throw().IfEquals(v => v.Property, 6); 141 | 142 | // Assert 143 | action.Should().NotThrow(); 144 | } 145 | 146 | [TestMethod] 147 | public void ThrowIfPropertyNotEquals_WhenPropertyNotEquals_ShouldThrow() 148 | { 149 | // Arrange 150 | var value = new { Property = 5 }; 151 | 152 | // Act 153 | Action action = () => value.Throw().IfNotEquals(v => v.Property, 6); 154 | 155 | // Assert 156 | action.Should() 157 | .ThrowExactly() 158 | .WithMessage($"Value should be equal to 6. (Parameter '{nameof(value)}: v => v.Property')"); 159 | } 160 | 161 | [TestMethod] 162 | public void ThrowIfPropertyNotEquals_WhenPropertyEquals_ShouldNotThrow() 163 | { 164 | // Arrange 165 | var value = new { Property = 5 }; 166 | 167 | // Act 168 | Action action = () => value.Throw().IfNotEquals(v => v.Property, 5); 169 | 170 | // Assert 171 | action.Should().NotThrow(); 172 | } 173 | } -------------------------------------------------------------------------------- /tests/UnitTests/ValidatableMethods/ValidatableMethods.TypesTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.ValidatableMethods; 2 | 3 | [TestClass] 4 | public class TypesTests 5 | { 6 | [TestMethod] 7 | public void ThrowIfType_WhenCompileTypesEqual_ShouldThrow() 8 | { 9 | // Arrange 10 | string str = "string"; 11 | 12 | // Act 13 | Action action = () => str.Throw().IfType(); 14 | 15 | // Assert 16 | action.Should() 17 | .ThrowExactly() 18 | .WithMessage($"Parameter should not be of type '{str.GetType().Name}'. (Parameter '{nameof(str)}')"); 19 | } 20 | 21 | [TestMethod] 22 | public void ThrowIfType_WhenRuntimeTypesEqual_ShouldThrow() 23 | { 24 | // Arrange 25 | object list = new List(); 26 | 27 | // Act 28 | Action action = () => list.Throw().IfType>(); 29 | 30 | // Assert 31 | action.Should() 32 | .ThrowExactly() 33 | .WithMessage($"Parameter should not be of type '{list.GetType().Name}'. (Parameter '{nameof(list)}')"); 34 | } 35 | 36 | [TestMethod] 37 | public void ThrowIfType_WhenCompileTimeTypeIsNotType_ShouldNotThrow() 38 | { 39 | // Arrange 40 | List list = new(); 41 | 42 | // Act 43 | Action action2 = () => list.Throw().IfType(); 44 | 45 | // Assert 46 | action2.Should().NotThrow(); 47 | } 48 | 49 | [TestMethod] 50 | public void ThrowIfNotType_WhenCompileTimeTypeIsNotType_ShouldThrow() 51 | { 52 | // Arrange 53 | string str = "string"; 54 | 55 | // Act 56 | Action action = () => str.Throw().IfNotType(); 57 | 58 | // Assert 59 | action.Should() 60 | .ThrowExactly() 61 | .WithMessage($"Parameter should be of type '{nameof(Int32)}'. (Parameter '{nameof(str)}')"); 62 | } 63 | 64 | [TestMethod] 65 | public void ThrowIfNotType_WhenCompileTimeTypesEqual_ShouldNotThrow() 66 | { 67 | // Arrange 68 | List list = new(); 69 | 70 | // Act 71 | Action action = () => list.Throw().IfNotType>(); 72 | 73 | // Assert 74 | action.Should().NotThrow(); 75 | } 76 | 77 | [TestMethod] 78 | public void ThrowIfNotType_WhenRuntimeTypesEquals_ShouldNotThrow() 79 | { 80 | // Arrange 81 | object list = new List(); 82 | 83 | // Act 84 | Action action = () => list.Throw().IfNotType>(); 85 | 86 | // Assert 87 | action.Should().NotThrow(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /tests/UnitTests/Validators/Validator.CollectionsTests.cs: -------------------------------------------------------------------------------- 1 | namespace Throw.UnitTests.Validators; 2 | 3 | [TestClass] 4 | public class CollectionsValidatorTests 5 | { 6 | [TestMethod] 7 | public void GetCollectionCount_WhenCollectionIsArray_ShouldReturnCollectionCount() 8 | { 9 | // Arrange 10 | var collection = new[] { 1 }; 11 | 12 | // Act 13 | var count = Validator.GetCollectionCount(collection); 14 | 15 | // Assert 16 | count.Should().Be(collection.Length); 17 | } 18 | 19 | [TestMethod] 20 | public void GetCollectionCount_WhenCollectionIsList_ShouldReturnCollectionCount() 21 | { 22 | // Arrange 23 | var collection = new List { 1 }; 24 | 25 | // Act 26 | var count = Validator.GetCollectionCount(collection); 27 | 28 | // Assert 29 | count.Should().Be(collection.Count); 30 | } 31 | 32 | [TestMethod] 33 | public void GetCollectionCount_WhenCollectionIsDictionary_ShouldReturnCollectionCount() 34 | { 35 | // Arrange 36 | var collection = new Dictionary { { 1, 1 } }; 37 | 38 | // Act 39 | var count = Validator.GetCollectionCount(collection); 40 | 41 | // Assert 42 | count.Should().Be(collection.Count); 43 | } 44 | 45 | [TestMethod] 46 | public void GetCollectionCount_WhenCollectionIsIEnumerable_ShouldReturnEnumeratedCount() 47 | { 48 | // Arrange 49 | var numItems = 10; 50 | var collection = Enumerable.Range(0, numItems); 51 | 52 | // Act 53 | var count = Validator.GetCollectionCount(collection); 54 | 55 | // Assert 56 | count.Should().Be(numItems); 57 | } 58 | 59 | [TestMethod] 60 | public void GetCollectionCount_WhenCollectionIsString_ShouldReturnStringLength() 61 | { 62 | // Arrange 63 | var str = "hello"; 64 | 65 | // Act 66 | var count = Validator.GetCollectionCount(str); 67 | 68 | // Assert 69 | count.Should().Be(str.Length); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tests/UnitTests/_usings.cs: -------------------------------------------------------------------------------- 1 | global using System; 2 | global using FluentAssertions; 3 | global using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | global using Throw.UnitTests.Utils; 5 | --------------------------------------------------------------------------------