diff --git a/src/GuardClauses/GuardAgainstExpressionExtensions.cs b/src/GuardClauses/GuardAgainstExpressionExtensions.cs index ae78d00..6351294 100644 --- a/src/GuardClauses/GuardAgainstExpressionExtensions.cs +++ b/src/GuardClauses/GuardAgainstExpressionExtensions.cs @@ -1,73 +1,60 @@ using System; using System.Threading.Tasks; +using System.Runtime.CompilerServices; namespace Ardalis.GuardClauses; public static partial class GuardClauseExtensions { /// - /// Throws an if evaluates to false for given + /// Validates the using the specified and throws an if it evaluates to true. + /// The should return true to indicate an invalid or undesirable state of the input. + /// If returns true, an is thrown, signifying that the input is invalid. /// - /// - /// - /// - /// - /// - /// if the evaluates to true - /// - public static T AgainstExpression(this IGuardClause guardClause, + /// The type of the input parameter. + /// The guard clause instance. + /// The function that evaluates the input. It should return true if the input is considered invalid or in a negative state. + /// The input to evaluate. + /// The message to include in the exception if the input is invalid. + /// The name of the parameter to include in the thrown exception, captured automatically from the input expression. + /// The if the evaluates to false, indicating a valid state. + /// Thrown when the validation function returns true, indicating that the input is invalid. + public static T Expression(this IGuardClause guardClause, Func func, T input, - string message) where T : struct + string message, + [CallerArgumentExpression("input")] string? parameterName = null) where T : struct { - if (!func(input)) + if (func(input)) { - throw new ArgumentException(message); + throw new ArgumentException(message, parameterName!); } return input; } /// - /// Throws an if evaluates to false for given + /// Validates the asynchronously and throws an if it evaluates to false for given + /// The should return true to indicate an invalid or undesirable state. + /// If returns true, indicating that the input is invalid, an is thrown. /// - /// - /// - /// - /// - /// + /// The type of the input parameter. + /// The function that evaluates the input. It should return true if the input is considered invalid or in a negative state. + /// The guard clause instance. + /// The input to evaluate. + /// The message to include in the exception if the input is invalid. + /// The name of the parameter to include in the thrown exception, captured automatically from the input expression. /// if the evaluates to true - /// - public static async Task AgainstExpressionAsync(this IGuardClause guardClause, + /// Thrown when the validation function returns true, indicating that the input is invalid. + public static async Task ExpressionAsync(this IGuardClause guardClause, Func> func, T input, - string message) where T : struct - { - if (!await func(input)) - { - throw new ArgumentException(message); - } - - return input; - } - - /// - /// Throws an if evaluates to false for given - /// - /// - /// - /// - /// - /// - /// The name of the parameter that is invalid - /// if the evaluates to true - /// - public static T AgainstExpression(this IGuardClause guardClause, Func func, - T input, string message, string paramName) where T : struct + string message, + [CallerArgumentExpression("input")] string? parameterName = null) where T : struct { - if (!func(input)) + if (await func(input)) { - throw new ArgumentException(message, paramName); + throw new ArgumentException(message, parameterName!); } return input; diff --git a/src/GuardClauses/GuardAgainstExpressionExtensionsDeprecated.cs b/src/GuardClauses/GuardAgainstExpressionExtensionsDeprecated.cs new file mode 100644 index 0000000..3f0ca0c --- /dev/null +++ b/src/GuardClauses/GuardAgainstExpressionExtensionsDeprecated.cs @@ -0,0 +1,78 @@ +using System; +using System.Threading.Tasks; + +namespace Ardalis.GuardClauses; + +public static partial class GuardClauseExtensions +{ + /// + /// Throws an if evaluates to false for given + /// + /// + /// + /// + /// + /// + /// if the evaluates to true + /// + [Obsolete("Deprecated: Switch to Expression for validation.")] + public static T AgainstExpression(this IGuardClause guardClause, + Func func, + T input, + string message) where T : struct + { + if (!func(input)) + { + throw new ArgumentException(message); + } + + return input; + } + + /// + /// Throws an if evaluates to false for given + /// + /// + /// + /// + /// + /// + /// if the evaluates to true + /// + [Obsolete("Deprecated: Switch to ExpressionAsync for asynchronous validation.")] + public static async Task AgainstExpressionAsync(this IGuardClause guardClause, + Func> func, + T input, + string message) where T : struct + { + if (!await func(input)) + { + throw new ArgumentException(message); + } + + return input; + } + + /// + /// Throws an if evaluates to false for given + /// + /// + /// + /// + /// + /// + /// The name of the parameter that is invalid + /// if the evaluates to true + /// + [Obsolete("Deprecated: Switch to Expression for validation.")] + public static T AgainstExpression(this IGuardClause guardClause, Func func, + T input, string message, string paramName) where T : struct + { + if (!func(input)) + { + throw new ArgumentException(message, paramName); + } + + return input; + } +} diff --git a/test/GuardClauses.UnitTests/GuardAgainstExpression.cs b/test/GuardClauses.UnitTests/GuardAgainstExpression.cs index 794ef44..ffd43b7 100644 --- a/test/GuardClauses.UnitTests/GuardAgainstExpression.cs +++ b/test/GuardClauses.UnitTests/GuardAgainstExpression.cs @@ -22,66 +22,56 @@ public static IEnumerable GetCustomStruct() }; } - [Theory] - [InlineData(10)] - public void GivenIntegerWhenTheExpressionEvaluatesToTrueDoesNothing(int test) + [Fact] + public void GivenIntegerWhenTheExpressionEvaluatesToTrueThrowsException() { - Guard.Against.AgainstExpression((x) => x == 10, test, "Value is not equal to 10"); + int testCase = 10; + Assert.Throws(() => Guard.Against.Expression((x) => x == 10, testCase, "Value cannot be 10")); } - [Theory] - [InlineData(10)] - public void GivenIntegerWhenTheExpressionEvaluatesToFalseThrowsException(int test) + [Fact] + public void GivenIntegerWhenTheExpressionEvaluatesToFalseDoesNothing() { - Assert.Throws(() => Guard.Against.AgainstExpression((x) => x == 5, test, "Value is not equal to 10")); + int testCase = 10; + Guard.Against.Expression((x) => x == 5, testCase, "Value cannot be 5"); } - [Theory] - [InlineData(1.1)] - public void GivenDoubleWhenTheExpressionEvaluatesToTrueDoesNothing(double test) + [Fact] + public void GivenDoubleWhenTheExpressionEvaluatesToTrueThrowsException() { - Guard.Against.AgainstExpression((x) => x == 1.1, test, "Value is not equal to 1.1"); + double testCase = 1.1; + Assert.Throws(() => Guard.Against.Expression((x) => x == 1.1, testCase, "Value cannot be 1.1")); } - [Theory] - [InlineData(1.1)] - public void GivenDoubleWhenTheExpressionEvaluatesToFalseThrowsException(int test) + [Fact] + public void GivenDoubleWhenTheExpressionEvaluatesToFalseDoesNothing() { - Assert.Throws(() => Guard.Against.AgainstExpression((x) => x == 5.0, test, "Value is not equal to 1.1")); + double testCase = 1.1; + Guard.Against.Expression((x) => x == 5.0, testCase, "Value cannot be 5.0"); } [Theory] [MemberData(nameof(GetCustomStruct))] - public void GivenCustomStructWhenTheExpressionEvaluatesToTrueDoesNothing(CustomStruct test) + public void GivenCustomStructWhenTheExpressionEvaluatesToTrueThrowsException(CustomStruct test) { - Guard.Against.AgainstExpression((x) => x.FieldName == "FieldValue", test, "FieldValue is not matching"); + Assert.Throws(() => Guard.Against.Expression((x) => x.FieldName == "FieldValue", test, "FieldValue is not matching")); } [Theory] [MemberData(nameof(GetCustomStruct))] - public void GivenCustomStructWhenTheExpressionEvaluatesToFalseThrowsException(CustomStruct test) + public void GivenCustomStructWhenTheExpressionEvaluatesToFalseDoesNothing(CustomStruct test) { - Assert.Throws(() => Guard.Against.AgainstExpression((x) => x.FieldName == "FailThis", test, "FieldValue is not matching")); - } - - [Theory] - [InlineData(null, "Value does not fall within the expected range.")] - [InlineData("Please provide correct value", "Please provide correct value")] - public void ErrorMessageMatchesExpected(string customMessage, string expectedMessage) - { - var exception = Assert.Throws(() => Guard.Against.AgainstExpression(x => x == 1, 2, customMessage)); - Assert.NotNull(exception); - Assert.NotNull(exception.Message); - Assert.Equal(expectedMessage, exception.Message); + Guard.Against.Expression((x) => x.FieldName == "FailThis", test, "FieldValue is not matching"); } [Fact] public void ErrorIncludesParamNameIfProvided() { string paramName = "testParamName"; - var exception = Assert.Throws(() => Guard.Against.AgainstExpression(x => x == 1, 2, "custom message", paramName)); + var exception = Assert.Throws(() => Guard.Against.Expression(x => x == 2, 2, "custom message", paramName)); Assert.NotNull(exception); Assert.NotNull(exception.Message); Assert.Equal(paramName, exception.ParamName); } + } diff --git a/test/GuardClauses.UnitTests/GuardAgainstExpressionDeprecated.cs b/test/GuardClauses.UnitTests/GuardAgainstExpressionDeprecated.cs new file mode 100644 index 0000000..ad32bc9 --- /dev/null +++ b/test/GuardClauses.UnitTests/GuardAgainstExpressionDeprecated.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using Ardalis.GuardClauses; +using Xunit; + +namespace GuardClauses.UnitTests; + +public class GuardAgainstExpressionDeprecated +{ + public struct CustomStruct + { + public string FieldName { get; set; } + } + + public static IEnumerable GetCustomStruct() + { + yield return new object[] { + new CustomStruct + { + FieldName = "FieldValue" + } + }; + } + + [Theory] + [InlineData(10)] + public void GivenIntegerWhenTheAgainstExpressionEvaluatesToTrueDoesNothing(int test) + { + Guard.Against.AgainstExpression((x) => x == 10, test, "Value is not equal to 10"); + } + + [Theory] + [InlineData(10)] + public void GivenIntegerWhenTheAgainstExpressionEvaluatesToFalseThrowsException(int test) + { + Assert.Throws(() => Guard.Against.AgainstExpression((x) => x == 5, test, "Value is not equal to 10")); + } + + [Theory] + [InlineData(1.1)] + public void GivenDoubleWhenTheAgainstExpressionEvaluatesToTrueDoesNothing(double test) + { + Guard.Against.AgainstExpression((x) => x == 1.1, test, "Value is not equal to 1.1"); + } + + [Theory] + [InlineData(1.1)] + public void GivenDoubleWhenTheAgainstExpressionEvaluatesToFalseThrowsException(int test) + { + Assert.Throws(() => Guard.Against.AgainstExpression((x) => x == 5.0, test, "Value is not equal to 1.1")); + } + + [Theory] + [MemberData(nameof(GetCustomStruct))] + public void GivenCustomStructWhenTheAgainstExpressionEvaluatesToTrueDoesNothing(CustomStruct test) + { + Guard.Against.AgainstExpression((x) => x.FieldName == "FieldValue", test, "FieldValue is not matching"); + } + + [Theory] + [MemberData(nameof(GetCustomStruct))] + public void GivenCustomStructWhenTheAgainstExpressionEvaluatesToFalseThrowsException(CustomStruct test) + { + Assert.Throws(() => Guard.Against.AgainstExpression((x) => x.FieldName == "FailThis", test, "FieldValue is not matching")); + } + + [Theory] + [InlineData(null, "Value does not fall within the expected range.")] + [InlineData("Please provide correct value", "Please provide correct value")] + public void ErrorMessageMatchesAgainstExpected(string customMessage, string expectedMessage) + { + var exception = Assert.Throws(() => Guard.Against.AgainstExpression(x => x == 1, 2, customMessage)); + Assert.NotNull(exception); + Assert.NotNull(exception.Message); + Assert.Equal(expectedMessage, exception.Message); + } + + [Fact] + public void ErrorIncludesParamNameIfProvidedInAgainstExpression() + { + string paramName = "testParamName"; + var exception = Assert.Throws(() => Guard.Against.AgainstExpression(x => x == 1, 2, "custom message", paramName)); + Assert.NotNull(exception); + Assert.NotNull(exception.Message); + Assert.Equal(paramName, exception.ParamName); + } +}