Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/nuget/Microsoft.NET.Test.Sdk-17.8.0
Browse files Browse the repository at this point in the history
  • Loading branch information
ardalis authored Dec 23, 2023
2 parents eed46a5 + f98cf0a commit d3ad148
Show file tree
Hide file tree
Showing 9 changed files with 229 additions and 84 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Setup .NET Core
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: '7.x'
dotnet-version: '8.x'
- name: Install dependencies
run: dotnet restore
- name: Build
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
# Required for a specific dotnet version that doesn't come with ubuntu-latest / windows-latest
# Visit bit.ly/2synnZl to see the list of SDKs that are pre-installed with ubuntu-latest / windows-latest
- name: Setup dotnet
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: 6.0.x

Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ public void SomeMethod(string something)
}
```

## YouTube Overview

[![Ardalis.GuardClauses on YouTube](http://img.youtube.com/vi/OkE2VeRM4mE/0.jpg)](http://www.youtube.com/watch?v=OkE2VeRM4mE "Improve Your Code with Ardalis.GuardClauses")

## Breaking Changes in v4

- OutOfRange for Enums now uses `EnumOutOfRange`
Expand Down
77 changes: 32 additions & 45 deletions src/GuardClauses/GuardAgainstExpressionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,73 +1,60 @@
using System;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;

namespace Ardalis.GuardClauses;

public static partial class GuardClauseExtensions
{
/// <summary>
/// Throws an <see cref="ArgumentException" /> if <paramref name="func"/> evaluates to false for given <paramref name="input"/>
/// Validates the <paramref name="input"/> using the specified <paramref name="func"/> and throws an <see cref="ArgumentException"/> if it evaluates to true.
/// The <paramref name="func"/> should return true to indicate an invalid or undesirable state of the input.
/// If <paramref name="func"/> returns true, an <see cref="ArgumentException"/> is thrown, signifying that the input is invalid.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <param name="guardClause"></param>
/// <param name="input"></param>
/// <param name="message"></param>
/// <returns><paramref name="input"/> if the <paramref name="func"/> evaluates to true </returns>
/// <exception cref="ArgumentException"></exception>
public static T AgainstExpression<T>(this IGuardClause guardClause,
/// <typeparam name="T">The type of the input parameter.</typeparam>
/// <param name="guardClause">The guard clause instance.</param>
/// <param name="func">The function that evaluates the input. It should return true if the input is considered invalid or in a negative state.</param>
/// <param name="input">The input to evaluate.</param>
/// <param name="message">The message to include in the exception if the input is invalid.</param>
/// <param name="parameterName">The name of the parameter to include in the thrown exception, captured automatically from the input expression.</param>
/// <returns>The <paramref name="input"/> if the <paramref name="func"/> evaluates to false, indicating a valid state.</returns>
/// <exception cref="ArgumentException">Thrown when the validation function returns true, indicating that the input is invalid.</exception>
public static T Expression<T>(this IGuardClause guardClause,
Func<T, bool> func,
T input,
string message) where T : struct
string message,
[CallerArgumentExpression("input")] string? parameterName = null) where T : struct

Check failure on line 26 in src/GuardClauses/GuardAgainstExpressionExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'CallerArgumentExpressionAttribute' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 26 in src/GuardClauses/GuardAgainstExpressionExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'CallerArgumentExpression' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 26 in src/GuardClauses/GuardAgainstExpressionExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'CallerArgumentExpressionAttribute' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 26 in src/GuardClauses/GuardAgainstExpressionExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'CallerArgumentExpression' could not be found (are you missing a using directive or an assembly reference?)
{
if (!func(input))
if (func(input))
{
throw new ArgumentException(message);
throw new ArgumentException(message, parameterName!);
}

return input;
}

/// <summary>
/// Throws an <see cref="ArgumentException" /> if <paramref name="func"/> evaluates to false for given <paramref name="input"/>
/// Validates the <paramref name="func"/> asynchronously and throws an <see cref="ArgumentException" /> if it evaluates to false for given <paramref name="input"/>
/// The <paramref name="func"/> should return true to indicate an invalid or undesirable state.
/// If <paramref name="func"/> returns true, indicating that the input is invalid, an <see cref="ArgumentException"/> is thrown.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <param name="guardClause"></param>
/// <param name="input"></param>
/// <param name="message"></param>
/// <typeparam name="T">The type of the input parameter.</typeparam>
/// <param name="func">The function that evaluates the input. It should return true if the input is considered invalid or in a negative state.</param>
/// <param name="guardClause">The guard clause instance.</param>
/// <param name="input">The input to evaluate.</param>
/// <param name="message">The message to include in the exception if the input is invalid.</param>
/// <param name="parameterName">The name of the parameter to include in the thrown exception, captured automatically from the input expression.</param>
/// <returns><paramref name="input"/> if the <paramref name="func"/> evaluates to true </returns>
/// <exception cref="ArgumentException"></exception>
public static async Task<T> AgainstExpressionAsync<T>(this IGuardClause guardClause,
/// <exception cref="ArgumentException">Thrown when the validation function returns true, indicating that the input is invalid.</exception>
public static async Task<T> ExpressionAsync<T>(this IGuardClause guardClause,
Func<T, Task<bool>> func,
T input,
string message) where T : struct
{
if (!await func(input))
{
throw new ArgumentException(message);
}

return input;
}

/// <summary>
/// Throws an <see cref="ArgumentException" /> if <paramref name="func"/> evaluates to false for given <paramref name="input"/>
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <param name="guardClause"></param>
/// <param name="input"></param>
/// <param name="message"></param>
/// <param name="paramName">The name of the parameter that is invalid</param>
/// <returns><paramref name="input"/> if the <paramref name="func"/> evaluates to true </returns>
/// <exception cref="ArgumentException"></exception>
public static T AgainstExpression<T>(this IGuardClause guardClause, Func<T, bool> func,
T input, string message, string paramName) where T : struct
string message,
[CallerArgumentExpression("input")] string? parameterName = null) where T : struct

Check failure on line 53 in src/GuardClauses/GuardAgainstExpressionExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'CallerArgumentExpressionAttribute' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 53 in src/GuardClauses/GuardAgainstExpressionExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'CallerArgumentExpression' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 53 in src/GuardClauses/GuardAgainstExpressionExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'CallerArgumentExpressionAttribute' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 53 in src/GuardClauses/GuardAgainstExpressionExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'CallerArgumentExpression' could not be found (are you missing a using directive or an assembly reference?)
{
if (!func(input))
if (await func(input))
{
throw new ArgumentException(message, paramName);
throw new ArgumentException(message, parameterName!);
}

return input;
Expand Down
78 changes: 78 additions & 0 deletions src/GuardClauses/GuardAgainstExpressionExtensionsDeprecated.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System;
using System.Threading.Tasks;

namespace Ardalis.GuardClauses;

public static partial class GuardClauseExtensions
{
/// <summary>
/// Throws an <see cref="ArgumentException" /> if <paramref name="func"/> evaluates to false for given <paramref name="input"/>
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <param name="guardClause"></param>
/// <param name="input"></param>
/// <param name="message"></param>
/// <returns><paramref name="input"/> if the <paramref name="func"/> evaluates to true </returns>
/// <exception cref="ArgumentException"></exception>
[Obsolete("Deprecated: Switch to Expression for validation.")]
public static T AgainstExpression<T>(this IGuardClause guardClause,
Func<T, bool> func,
T input,
string message) where T : struct
{
if (!func(input))
{
throw new ArgumentException(message);
}

return input;
}

/// <summary>
/// Throws an <see cref="ArgumentException" /> if <paramref name="func"/> evaluates to false for given <paramref name="input"/>
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <param name="guardClause"></param>
/// <param name="input"></param>
/// <param name="message"></param>
/// <returns><paramref name="input"/> if the <paramref name="func"/> evaluates to true </returns>
/// <exception cref="ArgumentException"></exception>
[Obsolete("Deprecated: Switch to ExpressionAsync for asynchronous validation.")]
public static async Task<T> AgainstExpressionAsync<T>(this IGuardClause guardClause,
Func<T, Task<bool>> func,
T input,
string message) where T : struct
{
if (!await func(input))
{
throw new ArgumentException(message);
}

return input;
}

/// <summary>
/// Throws an <see cref="ArgumentException" /> if <paramref name="func"/> evaluates to false for given <paramref name="input"/>
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <param name="guardClause"></param>
/// <param name="input"></param>
/// <param name="message"></param>
/// <param name="paramName">The name of the parameter that is invalid</param>
/// <returns><paramref name="input"/> if the <paramref name="func"/> evaluates to true </returns>
/// <exception cref="ArgumentException"></exception>
[Obsolete("Deprecated: Switch to Expression for validation.")]
public static T AgainstExpression<T>(this IGuardClause guardClause, Func<T, bool> func,
T input, string message, string paramName) where T : struct
{
if (!func(input))
{
throw new ArgumentException(message, paramName);
}

return input;
}
}
5 changes: 2 additions & 3 deletions src/GuardClauses/GuardClauses.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@
<RepositoryUrl>https://github.com/ardalis/guardclauses</RepositoryUrl>
<PackageTags>guard clause clauses assert assertion</PackageTags>
<PackageReleaseNotes>
* Add JetBrains.Annotations source code (#304)
* Added backwards compatibility (#291)
* Refactor AgainstExpression to Expression for Clarity and Consistency by @SimonNyvall in https://github.com/ardalis/GuardClauses/pull/317
</PackageReleaseNotes>
<Version>4.2.0</Version>
<Version>4.3.0</Version>
<AssemblyName>Ardalis.GuardClauses</AssemblyName>
<PackageIcon>icon.png</PackageIcon>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
Expand Down
54 changes: 22 additions & 32 deletions test/GuardClauses.UnitTests/GuardAgainstExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,66 +22,56 @@ public static IEnumerable<object[]> 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<ArgumentException>(() => 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<ArgumentException>(() => 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<ArgumentException>(() => 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<ArgumentException>(() => 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<ArgumentException>(() => 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<ArgumentException>(() => 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<ArgumentException>(() => 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<ArgumentException>(() => Guard.Against.AgainstExpression(x => x == 1, 2, "custom message", paramName));
var exception = Assert.Throws<ArgumentException>(() => Guard.Against.Expression(x => x == 2, 2, "custom message", paramName));
Assert.NotNull(exception);
Assert.NotNull(exception.Message);
Assert.Equal(paramName, exception.ParamName);
}

}
Loading

0 comments on commit d3ad148

Please sign in to comment.