Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Guard helper #2076

Merged
merged 4 commits into from Jan 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 10 additions & 10 deletions Src/FluentAssertions/AssertionExtensions.cs
Expand Up @@ -44,8 +44,8 @@ public static class AssertionExtensions
[Pure]
public static Action Invoking<T>(this T subject, Action<T> action)
{
Guard.ThrowIfArgumentIsNull(subject, nameof(subject));
Guard.ThrowIfArgumentIsNull(action, nameof(action));
Guard.ThrowIfArgumentIsNull(subject);
Guard.ThrowIfArgumentIsNull(action);

return () => action(subject);
}
Expand All @@ -59,8 +59,8 @@ public static Action Invoking<T>(this T subject, Action<T> action)
[Pure]
public static Func<TResult> Invoking<T, TResult>(this T subject, Func<T, TResult> action)
{
Guard.ThrowIfArgumentIsNull(subject, nameof(subject));
Guard.ThrowIfArgumentIsNull(action, nameof(action));
Guard.ThrowIfArgumentIsNull(subject);
Guard.ThrowIfArgumentIsNull(action);

return () => action(subject);
}
Expand Down Expand Up @@ -119,8 +119,8 @@ public static Func<Task> Awaiting<T>(this T subject, Func<T, ValueTask> action)
public static MemberExecutionTime<T> ExecutionTimeOf<T>(this T subject, Expression<Action<T>> action,
StartTimer createTimer = null)
{
Guard.ThrowIfArgumentIsNull(subject, nameof(subject));
Guard.ThrowIfArgumentIsNull(action, nameof(action));
Guard.ThrowIfArgumentIsNull(subject);
Guard.ThrowIfArgumentIsNull(action);

createTimer ??= () => new StopwatchTimer();

Expand Down Expand Up @@ -787,7 +787,7 @@ public static TypeAssertions Should(this Type subject)
[Pure]
public static TypeSelectorAssertions Should(this TypeSelector typeSelector)
{
Guard.ThrowIfArgumentIsNull(typeSelector, nameof(typeSelector));
Guard.ThrowIfArgumentIsNull(typeSelector);

return new TypeSelectorAssertions(typeSelector.ToArray());
}
Expand Down Expand Up @@ -822,7 +822,7 @@ public static MethodInfoAssertions Should(this MethodInfo methodInfo)
[Pure]
public static MethodInfoSelectorAssertions Should(this MethodInfoSelector methodSelector)
{
Guard.ThrowIfArgumentIsNull(methodSelector, nameof(methodSelector));
Guard.ThrowIfArgumentIsNull(methodSelector);

return new MethodInfoSelectorAssertions(methodSelector.ToArray());
}
Expand All @@ -847,7 +847,7 @@ public static PropertyInfoAssertions Should(this PropertyInfo propertyInfo)
[Pure]
public static PropertyInfoSelectorAssertions Should(this PropertyInfoSelector propertyInfoSelector)
{
Guard.ThrowIfArgumentIsNull(propertyInfoSelector, nameof(propertyInfoSelector));
Guard.ThrowIfArgumentIsNull(propertyInfoSelector);

return new PropertyInfoSelectorAssertions(propertyInfoSelector.ToArray());
}
Expand Down Expand Up @@ -912,7 +912,7 @@ public static TaskCompletionSourceAssertions<T> Should<T>(this TaskCompletionSou
/// An optional delegate that returns the current date and time in UTC format.
/// Will revert to <see cref="DateTime.UtcNow"/> if no delegate was provided.
/// </param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="eventSource"/> is Null.</exception>
/// <exception cref="ArgumentNullException"><paramref name="eventSource"/> is <see langword="null"/>.</exception>
public static IMonitor<T> Monitor<T>(this T eventSource, Func<DateTime> utcNow = null)
{
return new EventMonitor<T>(eventSource, utcNow ?? (() => DateTime.UtcNow));
Expand Down
4 changes: 2 additions & 2 deletions Src/FluentAssertions/AssertionOptions.cs
Expand Up @@ -25,7 +25,7 @@ public static EquivalencyAssertionOptions<T> CloneDefaults<T>()
internal static TOptions CloneDefaults<T, TOptions>(Func<EquivalencyAssertionOptions, TOptions> predicate)
where TOptions : EquivalencyAssertionOptions<T>
{
Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate));
Guard.ThrowIfArgumentIsNull(predicate);

return predicate(defaults);
}
Expand All @@ -40,7 +40,7 @@ public static EquivalencyAssertionOptions<T> CloneDefaults<T>()
public static void AssertEquivalencyUsing(
Func<EquivalencyAssertionOptions, EquivalencyAssertionOptions> defaultsConfigurer)
{
Guard.ThrowIfArgumentIsNull(defaultsConfigurer, nameof(defaultsConfigurer));
Guard.ThrowIfArgumentIsNull(defaultsConfigurer);

defaults = defaultsConfigurer(defaults);
}
Expand Down
30 changes: 15 additions & 15 deletions Src/FluentAssertions/Collections/GenericCollectionAssertions.cs
Expand Up @@ -106,7 +106,7 @@ public GenericCollectionAssertions(TCollection actualValue)
/// <exception cref="ArgumentNullException"><paramref name="expectedType"/> is <see langword="null"/>.</exception>
public AndConstraint<TAssertions> AllBeAssignableTo(Type expectedType, string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(expectedType, nameof(expectedType));
Guard.ThrowIfArgumentIsNull(expectedType);

Execute.Assertion
.BecauseOf(because, becauseArgs)
Expand Down Expand Up @@ -182,7 +182,7 @@ public AndConstraint<TAssertions> AllBeAssignableTo(Type expectedType, string be
string because = "",
params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(config, nameof(config));
Guard.ThrowIfArgumentIsNull(config);

TExpectation[] repeatedExpectation = RepeatAsManyAs(expectation, Subject).ToArray();

Expand Down Expand Up @@ -251,7 +251,7 @@ public AndConstraint<TAssertions> AllBeAssignableTo(Type expectedType, string be
/// <exception cref="ArgumentNullException"><paramref name="expectedType"/> is <see langword="null"/>.</exception>
public AndConstraint<TAssertions> AllBeOfType(Type expectedType, string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(expectedType, nameof(expectedType));
Guard.ThrowIfArgumentIsNull(expectedType);

Execute.Assertion
.BecauseOf(because, becauseArgs)
Expand Down Expand Up @@ -353,7 +353,7 @@ public AndConstraint<TAssertions> BeEmpty(string because = "", params object[] b
Func<EquivalencyAssertionOptions<TExpectation>, EquivalencyAssertionOptions<TExpectation>> config, string because = "",
params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(config, nameof(config));
Guard.ThrowIfArgumentIsNull(config);

EquivalencyAssertionOptions<IEnumerable<TExpectation>> options = config(AssertionOptions.CloneDefaults<TExpectation>()).AsCollection();

Expand Down Expand Up @@ -713,7 +713,7 @@ public AndConstraint<TAssertions> BeNullOrEmpty(string because = "", params obje
/// <exception cref="ArgumentNullException"><paramref name="predicate"/> is <see langword="null"/>.</exception>
public AndWhichConstraint<TAssertions, T> Contain(Expression<Func<T, bool>> predicate, string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate));
Guard.ThrowIfArgumentIsNull(predicate);

bool success = Execute.Assertion
.BecauseOf(because, becauseArgs)
Expand Down Expand Up @@ -838,7 +838,7 @@ public AndConstraint<TAssertions> Contain(IEnumerable<T> expected, string becaus
public AndWhichConstraint<TAssertions, T> ContainEquivalentOf<TExpectation>(TExpectation expectation, Func<EquivalencyAssertionOptions<TExpectation>,
EquivalencyAssertionOptions<TExpectation>> config, string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(config, nameof(config));
Guard.ThrowIfArgumentIsNull(config);

bool success = Execute.Assertion
.BecauseOf(because, becauseArgs)
Expand Down Expand Up @@ -1110,7 +1110,7 @@ public AndConstraint<TAssertions> ContainItemsAssignableTo<TExpectation>(string
public AndWhichConstraint<TAssertions, T> ContainSingle(Expression<Func<T, bool>> predicate,
string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate));
Guard.ThrowIfArgumentIsNull(predicate);

string expectationPrefix =
"Expected {context:collection} to contain a single item matching {0}{reason}, ";
Expand Down Expand Up @@ -2109,7 +2109,7 @@ public AndConstraint<TAssertions> NotBeNullOrEmpty(string because = "", params o
/// <exception cref="ArgumentNullException"><paramref name="predicate"/> is <see langword="null"/>.</exception>
public AndConstraint<TAssertions> NotContain(Expression<Func<T, bool>> predicate, string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate));
Guard.ThrowIfArgumentIsNull(predicate);

bool success = Execute.Assertion
.BecauseOf(because, becauseArgs)
Expand Down Expand Up @@ -2232,7 +2232,7 @@ public AndConstraint<TAssertions> NotContain(IEnumerable<T> unexpected, string b
public AndConstraint<TAssertions> NotContainEquivalentOf<TExpectation>(TExpectation unexpected, Func<EquivalencyAssertionOptions<TExpectation>,
EquivalencyAssertionOptions<TExpectation>> config, string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(config, nameof(config));
Guard.ThrowIfArgumentIsNull(config);

bool success = Execute.Assertion
.BecauseOf(because, becauseArgs)
Expand Down Expand Up @@ -2465,7 +2465,7 @@ public AndConstraint<TAssertions> NotContainInConsecutiveOrder(params T[] unexpe
public AndConstraint<TAssertions> NotContainNulls<TKey>(Expression<Func<T, TKey>> predicate, string because = "", params object[] becauseArgs)
where TKey : class
{
Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate));
Guard.ThrowIfArgumentIsNull(predicate);

bool success = Execute.Assertion
.BecauseOf(because, becauseArgs)
Expand Down Expand Up @@ -2693,7 +2693,7 @@ public AndConstraint<TAssertions> NotHaveCount(int unexpected, string because =
public AndConstraint<TAssertions> OnlyContain(
Expression<Func<T, bool>> predicate, string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate));
Guard.ThrowIfArgumentIsNull(predicate);

Func<T, bool> compiledPredicate = predicate.Compile();

Expand Down Expand Up @@ -2731,7 +2731,7 @@ public AndConstraint<TAssertions> NotHaveCount(int unexpected, string because =
/// <exception cref="ArgumentNullException"><paramref name="predicate"/> is <see langword="null"/>.</exception>
public AndConstraint<TAssertions> OnlyHaveUniqueItems<TKey>(Expression<Func<T, TKey>> predicate, string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate));
Guard.ThrowIfArgumentIsNull(predicate);

bool success = Execute.Assertion
.BecauseOf(because, becauseArgs)
Expand Down Expand Up @@ -3173,7 +3173,7 @@ protected static IEnumerable<TExpectation> RepeatAsManyAs<TExpectation>(TExpecta

protected void AssertCollectionEndsWith<TActual, TExpectation>(IEnumerable<TActual> actual, ICollection<TExpectation> expected, Func<TActual, TExpectation, bool> equalityComparison, string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(equalityComparison, nameof(equalityComparison));
Guard.ThrowIfArgumentIsNull(equalityComparison);

Execute.Assertion
.BecauseOf(because, becauseArgs)
Expand All @@ -3195,7 +3195,7 @@ protected static IEnumerable<TExpectation> RepeatAsManyAs<TExpectation>(TExpecta

protected void AssertCollectionStartsWith<TActual, TExpectation>(IEnumerable<TActual> actualItems, ICollection<TExpectation> expected, Func<TActual, TExpectation, bool> equalityComparison, string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(equalityComparison, nameof(equalityComparison));
Guard.ThrowIfArgumentIsNull(equalityComparison);

Execute.Assertion
.BecauseOf(because, becauseArgs)
Expand All @@ -3213,7 +3213,7 @@ protected static IEnumerable<TExpectation> RepeatAsManyAs<TExpectation>(TExpecta
protected void AssertSubjectEquality<TExpectation>(IEnumerable<TExpectation> expectation, Func<T, TExpectation, bool> equalityComparison,
string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(equalityComparison, nameof(equalityComparison));
Guard.ThrowIfArgumentIsNull(equalityComparison);

bool subjectIsNull = Subject is null;
bool expectationIsNull = expectation is null;
Expand Down
Expand Up @@ -210,7 +210,7 @@ public GenericDictionaryAssertions(TCollection keyValuePairs)
Func<EquivalencyAssertionOptions<TExpectation>, EquivalencyAssertionOptions<TExpectation>> config, string because = "",
params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(config, nameof(config));
Guard.ThrowIfArgumentIsNull(config);

EquivalencyAssertionOptions<TExpectation> options = config(AssertionOptions.CloneDefaults<TExpectation>());

Expand Down
Expand Up @@ -125,7 +125,7 @@ public AndConstraint<TAssertions> BeEquivalentTo(IEnumerable<string> expectation
Func<EquivalencyAssertionOptions<string>, EquivalencyAssertionOptions<string>> config, string because = "",
params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(config, nameof(config));
Guard.ThrowIfArgumentIsNull(config);

EquivalencyAssertionOptions<IEnumerable<string>> options = config(AssertionOptions.CloneDefaults<string>()).AsCollection();

Expand Down Expand Up @@ -187,7 +187,7 @@ public AndConstraint<TAssertions> BeEquivalentTo(IEnumerable<string> expectation
string because = "",
params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(config, nameof(config));
Guard.ThrowIfArgumentIsNull(config);

string[] repeatedExpectation = RepeatAsManyAs(expectation, Subject).ToArray();

Expand Down
35 changes: 30 additions & 5 deletions Src/FluentAssertions/Common/Guard.cs
@@ -1,12 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;

namespace FluentAssertions.Common;

internal static class Guard
{
public static void ThrowIfArgumentIsNull<T>([ValidatedNotNull] T obj, string paramName)
public static void ThrowIfArgumentIsNull<T>([ValidatedNotNull] T obj, [CallerArgumentExpression(nameof(obj))] string paramName = "")
{
if (obj is null)
{
Expand All @@ -22,7 +23,7 @@ public static void ThrowIfArgumentIsNull<T>([ValidatedNotNull] T obj, string par
}
}

public static void ThrowIfArgumentIsNullOrEmpty([ValidatedNotNull] string str, string paramName)
public static void ThrowIfArgumentIsNullOrEmpty([ValidatedNotNull] string str, [CallerArgumentExpression(nameof(str))] string paramName = "")
{
if (string.IsNullOrEmpty(str))
{
Expand All @@ -40,7 +41,7 @@ public static void ThrowIfArgumentIsNullOrEmpty([ValidatedNotNull] string str, s
}
}

public static void ThrowIfArgumentIsOutOfRange<T>(T value, string paramName)
public static void ThrowIfArgumentIsOutOfRange<T>(T value, [CallerArgumentExpression(nameof(value))] string paramName = "")
where T : Enum
{
if (!Enum.IsDefined(typeof(T), value))
Expand All @@ -49,7 +50,7 @@ public static void ThrowIfArgumentIsOutOfRange<T>(T value, string paramName)
}
}

public static void ThrowIfArgumentContainsNull<T>(IEnumerable<T> values, string paramName)
public static void ThrowIfArgumentContainsNull<T>(IEnumerable<T> values, [CallerArgumentExpression(nameof(values))] string paramName = "")
{
if (values.Any(t => t is null))
{
Expand All @@ -73,14 +74,38 @@ public static void ThrowIfArgumentIsEmpty(string str, string paramName, string m
}
}

public static void ThrowIfArgumentIsNegative(TimeSpan timeSpan, string paramName)
public static void ThrowIfArgumentIsNegative(TimeSpan timeSpan, [CallerArgumentExpression(nameof(timeSpan))] string paramName = "")
{
if (timeSpan < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(paramName, "The value must be non-negative.");
}
}

public static void ThrowIfArgumentIsNegative(float value, [CallerArgumentExpression(nameof(value))] string paramName = "")
{
if (value < 0)
{
throw new ArgumentOutOfRangeException(paramName, "The value must be non-negative.");
}
}

public static void ThrowIfArgumentIsNegative(double value, [CallerArgumentExpression(nameof(value))] string paramName = "")
{
if (value < 0)
{
throw new ArgumentOutOfRangeException(paramName, "The value must be non-negative.");
}
}

public static void ThrowIfArgumentIsNegative(decimal value, [CallerArgumentExpression(nameof(value))] string paramName = "")
{
if (value < 0)
{
throw new ArgumentOutOfRangeException(paramName, "The value must be non-negative.");
}
}

/// <summary>
/// Workaround to make dotnet_code_quality.null_check_validation_methods work
/// https://github.com/dotnet/roslyn-analyzers/issues/3451#issuecomment-606690452
Expand Down
Expand Up @@ -44,7 +44,7 @@ internal class ReadOnlyNonGenericCollectionWrapper<TCollection, TItem> : ICollec
/// <exception cref="ArgumentNullException"><paramref name="collection"/> is <see langword="null"/>.</exception>
public ReadOnlyNonGenericCollectionWrapper(TCollection collection)
{
Guard.ThrowIfArgumentIsNull(collection, nameof(collection));
Guard.ThrowIfArgumentIsNull(collection);

UnderlyingCollection = collection;
}
Expand Down
2 changes: 1 addition & 1 deletion Src/FluentAssertions/Data/DataColumnAssertions.cs
Expand Up @@ -112,7 +112,7 @@ public AndConstraint<DataColumnAssertions> BeEquivalentTo(DataColumn expectation
/// <exception cref="ArgumentNullException"><paramref name="config"/> is <see langword="null"/>.</exception>
public AndConstraint<DataColumnAssertions> BeEquivalentTo(DataColumn expectation, Func<IDataEquivalencyAssertionOptions<DataColumn>, IDataEquivalencyAssertionOptions<DataColumn>> config, string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(config, nameof(config));
Guard.ThrowIfArgumentIsNull(config);

IDataEquivalencyAssertionOptions<DataColumn> options = config(AssertionOptions.CloneDefaults<DataColumn, DataEquivalencyAssertionOptions<DataColumn>>(e => new(e)));

Expand Down
2 changes: 1 addition & 1 deletion Src/FluentAssertions/Data/DataRowAssertions.cs
Expand Up @@ -177,7 +177,7 @@ public AndConstraint<DataRowAssertions<TDataRow>> BeEquivalentTo(DataRow expecta
/// <exception cref="ArgumentNullException"><paramref name="config"/> is <see langword="null"/>.</exception>
public AndConstraint<DataRowAssertions<TDataRow>> BeEquivalentTo(DataRow expectation, Func<IDataEquivalencyAssertionOptions<DataRow>, IDataEquivalencyAssertionOptions<DataRow>> config, string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(config, nameof(config));
Guard.ThrowIfArgumentIsNull(config);

IDataEquivalencyAssertionOptions<DataRow> options = config(AssertionOptions.CloneDefaults<DataRow, DataEquivalencyAssertionOptions<DataRow>>(e => new(e)));

Expand Down
2 changes: 1 addition & 1 deletion Src/FluentAssertions/Data/DataSetAssertions.cs
Expand Up @@ -229,7 +229,7 @@ public AndConstraint<DataSetAssertions<TDataSet>> BeEquivalentTo(DataSet expecta
/// <exception cref="ArgumentNullException"><paramref name="config"/> is <see langword="null"/>.</exception>
public AndConstraint<DataSetAssertions<TDataSet>> BeEquivalentTo(DataSet expectation, Func<IDataEquivalencyAssertionOptions<DataSet>, IDataEquivalencyAssertionOptions<DataSet>> config, string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(config, nameof(config));
Guard.ThrowIfArgumentIsNull(config);

IDataEquivalencyAssertionOptions<DataSet> options = config(AssertionOptions.CloneDefaults<DataSet, DataEquivalencyAssertionOptions<DataSet>>(e => new(e)));

Expand Down
2 changes: 1 addition & 1 deletion Src/FluentAssertions/Data/DataTableAssertions.cs
Expand Up @@ -242,7 +242,7 @@ public AndConstraint<DataTableAssertions<TDataTable>> BeEquivalentTo(DataTable e
/// <exception cref="ArgumentNullException"><paramref name="config"/> is <see langword="null"/>.</exception>
public AndConstraint<DataTableAssertions<TDataTable>> BeEquivalentTo(DataTable expectation, Func<IDataEquivalencyAssertionOptions<DataTable>, IDataEquivalencyAssertionOptions<DataTable>> config, string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(config, nameof(config));
Guard.ThrowIfArgumentIsNull(config);

IDataEquivalencyAssertionOptions<DataTable> options = config(AssertionOptions.CloneDefaults<DataTable, DataEquivalencyAssertionOptions<DataTable>>(e => new(e)));

Expand Down