Skip to content

Commit

Permalink
Merge pull request #2076 from jnyrup/exception_docs
Browse files Browse the repository at this point in the history
Improve `Guard` helper
  • Loading branch information
jnyrup committed Jan 1, 2023
2 parents 2ca12e3 + f535b98 commit 451330c
Show file tree
Hide file tree
Showing 52 changed files with 278 additions and 265 deletions.
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

0 comments on commit 451330c

Please sign in to comment.