Skip to content

Commit

Permalink
[WIP] ParameterInfoSelector
Browse files Browse the repository at this point in the history
TODO: ThatAre... (IsLcid, IsOptional, etc.)
  • Loading branch information
0xced committed Jan 13, 2024
1 parent f23f761 commit 1dbfb54
Show file tree
Hide file tree
Showing 9 changed files with 546 additions and 4 deletions.
21 changes: 21 additions & 0 deletions Src/FluentAssertions/AssertionExtensions.cs
Expand Up @@ -802,6 +802,20 @@ public static ParameterInfoAssertions Should(this ParameterInfo parameterInfo)
return new ParameterInfoAssertions(parameterInfo);
}

/// <summary>
/// Returns a <see cref="ParameterInfoSelectorAssertions"/> object that can be used to assert the properties returned by the
/// current <see cref="ParameterInfoSelector"/>.
/// </summary>
/// <seealso cref="TypeAssertions"/>
/// <exception cref="ArgumentNullException"><paramref name="parameterInfoSelector"/> is <see langword="null"/>.</exception>
[Pure]
public static ParameterInfoSelectorAssertions Should(this ParameterInfoSelector parameterInfoSelector)
{
Guard.ThrowIfArgumentIsNull(parameterInfoSelector);

return new ParameterInfoSelectorAssertions(parameterInfoSelector.ToArray());
}

/// <summary>
/// Returns a <see cref="PropertyInfoAssertions"/> object that can be used to assert the
/// current <see cref="PropertyInfoSelector"/>.
Expand Down Expand Up @@ -1007,6 +1021,13 @@ public static void Should(this MethodInfoSelectorAssertions _)
InvalidShouldCall();
}

/// <inheritdoc cref="Should(ExecutionTimeAssertions)" />
[Obsolete("You are asserting the 'AndConstraint' itself. Remove the 'Should()' method directly following 'And'", error: true)]
public static void Should(this ParameterInfoSelectorAssertions _)
{
InvalidShouldCall();
}

/// <inheritdoc cref="Should(ExecutionTimeAssertions)" />
[Obsolete("You are asserting the 'AndConstraint' itself. Remove the 'Should()' method directly following 'And'", error: true)]
public static void Should(this PropertyInfoSelectorAssertions _)
Expand Down
22 changes: 22 additions & 0 deletions Src/FluentAssertions/TypeExtensions.cs
Expand Up @@ -58,6 +58,28 @@ public static MethodInfoSelector Methods(this TypeSelector typeSelector)
return new MethodInfoSelector(typeSelector.ToList());
}

/// <summary>
/// Returns a parameter selector for the current <see cref="MethodInfo"/>.
/// </summary>
/// <exception cref="ArgumentNullException"><paramref name="method"/> is <see langword="null"/>.</exception>
public static ParameterInfoSelector Parameters(this MethodInfo method)
{
Guard.ThrowIfArgumentIsNull(method);

return new ParameterInfoSelector(method);
}

/// <summary>
/// Returns a parameter selector for the current collection of <see cref="MethodInfo"/>.
/// </summary>
/// <exception cref="ArgumentNullException"><paramref name="methods"/> is <see langword="null"/>.</exception>
public static ParameterInfoSelector Parameters(this IEnumerable<MethodInfo> methods)
{
Guard.ThrowIfArgumentIsNull(methods);

return new ParameterInfoSelector(methods);
}

/// <summary>
/// Returns a property selector for the current <see cref="Type"/>.
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions Src/FluentAssertions/Types/ParameterInfoAssertions.cs
Expand Up @@ -14,6 +14,11 @@ public ParameterInfoAssertions(ParameterInfo parameterInfo)
{
}

internal static string GetDescriptionFor(ParameterInfo parameter)
{
return parameter?.Name ?? string.Empty;
}

internal override string SubjectDescription => Subject.Name;

/// <summary>
Expand Down
211 changes: 211 additions & 0 deletions Src/FluentAssertions/Types/ParameterInfoSelector.cs
@@ -0,0 +1,211 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using FluentAssertions.Common;

namespace FluentAssertions.Types;

/// <summary>
/// Allows for fluent selection of parameters of a method through reflection.
/// </summary>
public class ParameterInfoSelector : IEnumerable<ParameterInfo>
{
private IEnumerable<ParameterInfo> selectedParameters;

/// <summary>
/// Initializes a new instance of the <see cref="ParameterInfoSelector"/> class.
/// </summary>
/// <param name="method">The method from which to select parameters.</param>
/// <exception cref="ArgumentNullException"><paramref name="method"/> is <see langword="null"/>.</exception>
public ParameterInfoSelector(MethodInfo method)
: this(new[] { method })
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ParameterInfoSelector"/> class.
/// </summary>
/// <param name="methods">The methods from which to select parameters.</param>
/// <exception cref="ArgumentNullException"><paramref name="methods"/> is or contains <see langword="null"/>.</exception>
public ParameterInfoSelector(IEnumerable<MethodInfo> methods)
{
Guard.ThrowIfArgumentIsNull(methods);
Guard.ThrowIfArgumentContainsNull(methods);

selectedParameters = methods.SelectMany(method => method.GetParameters());
}

/// <summary>
/// Only select the parameters that are input parameters.
/// </summary>
public ParameterInfoSelector ThatAreInput
{
get
{
selectedParameters = selectedParameters.Where(parameter => parameter.IsIn);
return this;
}
}

/// <summary>
/// Only select the parameters that are not input parameters.
/// </summary>
public ParameterInfoSelector ThatAreNotInput
{
get
{
selectedParameters = selectedParameters.Where(parameter => !parameter.IsIn);
return this;
}
}

/// <summary>
/// Only select the parameters that are output parameters.
/// </summary>
public ParameterInfoSelector ThatAreOutput
{
get
{
selectedParameters = selectedParameters.Where(parameter => parameter.IsOut);
return this;
}
}

/// <summary>
/// Only select the parameters that are not output parameters.
/// </summary>
public ParameterInfoSelector ThatAreNotOutput
{
get
{
selectedParameters = selectedParameters.Where(parameter => !parameter.IsOut);
return this;
}
}

/// <summary>
/// Only select the parameters that have a default value
/// </summary>
public ParameterInfoSelector ThatHaveDefaultValue
{
get
{
selectedParameters = selectedParameters.Where(parameter => parameter.HasDefaultValue);
return this;
}
}

/// <summary>
/// Only select the parameters that do not have a default value
/// </summary>
public ParameterInfoSelector ThatDoNotHaveDefaultValue
{
get
{
selectedParameters = selectedParameters.Where(parameter => !parameter.HasDefaultValue);
return this;
}
}

/// <summary>
/// Only select the parameters that are decorated with an attribute of the specified type.
/// </summary>
public ParameterInfoSelector ThatAreDecoratedWith<TAttribute>()
where TAttribute : Attribute
{
selectedParameters = selectedParameters.Where(parameter => parameter.IsDecoratedWith<TAttribute>());
return this;
}

/// <summary>
/// Only select the parameters that are decorated with, or inherits from a parent class, an attribute of the specified type.
/// </summary>
public ParameterInfoSelector ThatAreDecoratedWithOrInherit<TAttribute>()
where TAttribute : Attribute
{
selectedParameters = selectedParameters.Where(parameter => parameter.IsDecoratedWithOrInherit<TAttribute>());
return this;
}

/// <summary>
/// Only select the parameters that are not decorated with an attribute of the specified type.
/// </summary>
public ParameterInfoSelector ThatAreNotDecoratedWith<TAttribute>()
where TAttribute : Attribute
{
selectedParameters = selectedParameters.Where(parameter => !parameter.IsDecoratedWith<TAttribute>());
return this;
}

/// <summary>
/// Only select the parameters that are not decorated with and does not inherit from a parent class an attribute of the specified type.
/// </summary>
public ParameterInfoSelector ThatAreNotDecoratedWithOrInherit<TAttribute>()
where TAttribute : Attribute
{
selectedParameters = selectedParameters.Where(parameter => !parameter.IsDecoratedWithOrInherit<TAttribute>());
return this;
}

/// <summary>
/// Only select the parameters that return the specified type
/// </summary>
public ParameterInfoSelector OfType<TReturn>()
{
selectedParameters = selectedParameters.Where(parameter => parameter.ParameterType == typeof(TReturn));
return this;
}

/// <summary>
/// Only select the parameters that do not return the specified type
/// </summary>
public ParameterInfoSelector NotOfType<TReturn>()
{
selectedParameters = selectedParameters.Where(parameter => parameter.ParameterType != typeof(TReturn));
return this;
}

/// <summary>
/// Select the types of the parameters
/// </summary>
public TypeSelector Types()
{
var returnTypes = selectedParameters.Select(parameter => parameter.ParameterType);

return new TypeSelector(returnTypes);
}

/// <summary>
/// The resulting <see cref="ParameterInfo"/> objects.
/// </summary>
public ParameterInfo[] ToArray()
{
return selectedParameters.ToArray();
}

/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// A <see cref="System.Collections.Generic.IEnumerator{T}"/> that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>1</filterpriority>
public IEnumerator<ParameterInfo> GetEnumerator()
{
return selectedParameters.GetEnumerator();
}

/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>2</filterpriority>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}

0 comments on commit 1dbfb54

Please sign in to comment.