Skip to content

Commit

Permalink
Merge branch 'main' into bug/issue-788-Raise-EventWith-default-constr…
Browse files Browse the repository at this point in the history
…uctor
  • Loading branch information
Mihnea Rădulescu committed May 27, 2024
2 parents a524189 + b7ff02c commit ee276f3
Show file tree
Hide file tree
Showing 107 changed files with 460 additions and 1,206 deletions.
58 changes: 25 additions & 33 deletions src/NSubstitute/Compatibility/DiagnosticsNullabilityAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,64 +22,56 @@ internal sealed class MaybeNullAttribute : Attribute { }
internal sealed class NotNullAttribute : Attribute { }

/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter may be null even if the corresponding type disallows it.</summary>
/// <remarks>Initializes the attribute with the specified return value condition.</remarks>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter may be null.
/// </param>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
internal sealed class MaybeNullWhenAttribute : Attribute
internal sealed class MaybeNullWhenAttribute(bool returnValue) : Attribute
{
/// <summary>Initializes the attribute with the specified return value condition.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter may be null.
/// </param>
public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;

/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }
public bool ReturnValue { get; } = returnValue;
}

/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
/// <remarks>Initializes the attribute with the specified return value condition.</remarks>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter will not be null.
/// </param>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
internal sealed class NotNullWhenAttribute : Attribute
internal sealed class NotNullWhenAttribute(bool returnValue) : Attribute
{
/// <summary>Initializes the attribute with the specified return value condition.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter will not be null.
/// </param>
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;

/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }
public bool ReturnValue { get; } = returnValue;
}

/// <summary>Specifies that the output will be non-null if the named parameter is non-null.</summary>
/// <remarks>Initializes the attribute with the associated parameter name.</remarks>
/// <param name="parameterName">
/// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null.
/// </param>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
internal sealed class NotNullIfNotNullAttribute : Attribute
internal sealed class NotNullIfNotNullAttribute(string parameterName) : Attribute
{
/// <summary>Initializes the attribute with the associated parameter name.</summary>
/// <param name="parameterName">
/// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null.
/// </param>
public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName;

/// <summary>Gets the associated parameter name.</summary>
public string ParameterName { get; }
public string ParameterName { get; } = parameterName;
}

/// <summary>Applied to a method that will never return under any circumstance.</summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
internal sealed class DoesNotReturnAttribute : Attribute { }

/// <summary>Specifies that the method will not return if the associated Boolean parameter is passed the specified value.</summary>
/// <remarks>Initializes the attribute with the specified parameter value.</remarks>
/// <param name="parameterValue">
/// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to
/// the associated parameter matches this value.
/// </param>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
internal sealed class DoesNotReturnIfAttribute : Attribute
internal sealed class DoesNotReturnIfAttribute(bool parameterValue) : Attribute
{
/// <summary>Initializes the attribute with the specified parameter value.</summary>
/// <param name="parameterValue">
/// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to
/// the associated parameter matches this value.
/// </param>
public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue;

/// <summary>Gets the condition parameter value.</summary>
public bool ParameterValue { get; }
public bool ParameterValue { get; } = parameterValue;
}

/// <summary>Specifies that the method or property will ensure that the listed field and property members have not-null values.</summary>
Expand Down
11 changes: 2 additions & 9 deletions src/NSubstitute/Core/ArgumentSpecificationDequeue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,10 @@

namespace NSubstitute.Core;

public class ArgumentSpecificationDequeue : IArgumentSpecificationDequeue
public class ArgumentSpecificationDequeue(Func<IList<IArgumentSpecification>> dequeueAllQueuedArgSpecs) : IArgumentSpecificationDequeue
{
private static readonly IArgumentSpecification[] EmptySpecifications = [];

private readonly Func<IList<IArgumentSpecification>> _dequeueAllQueuedArgSpecs;

public ArgumentSpecificationDequeue(Func<IList<IArgumentSpecification>> dequeueAllQueuedArgSpecs)
{
_dequeueAllQueuedArgSpecs = dequeueAllQueuedArgSpecs;
}

public IList<IArgumentSpecification> DequeueAllArgumentSpecificationsForMethod(int parametersCount)
{
if (parametersCount == 0)
Expand All @@ -24,7 +17,7 @@ public IList<IArgumentSpecification> DequeueAllArgumentSpecificationsForMethod(i
return EmptySpecifications;
}

var queuedArgSpecifications = _dequeueAllQueuedArgSpecs.Invoke();
var queuedArgSpecifications = dequeueAllQueuedArgSpecs.Invoke();
return queuedArgSpecifications;
}

Expand Down
13 changes: 3 additions & 10 deletions src/NSubstitute/Core/Arguments/AnyArgumentMatcher.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
namespace NSubstitute.Core.Arguments;

public class AnyArgumentMatcher : IArgumentMatcher
public class AnyArgumentMatcher(Type typeArgMustBeCompatibleWith) : IArgumentMatcher
{
private readonly Type _typeArgMustBeCompatibleWith;
public override string ToString() => "any " + typeArgMustBeCompatibleWith.GetNonMangledTypeName();

public AnyArgumentMatcher(Type typeArgMustBeCompatibleWith)
{
_typeArgMustBeCompatibleWith = typeArgMustBeCompatibleWith;
}

public override string ToString() => "any " + _typeArgMustBeCompatibleWith.GetNonMangledTypeName();

public bool IsSatisfiedBy(object? argument) => argument.IsCompatibleWith(_typeArgMustBeCompatibleWith);
public bool IsSatisfiedBy(object? argument) => argument.IsCompatibleWith(typeArgMustBeCompatibleWith);
}
15 changes: 4 additions & 11 deletions src/NSubstitute/Core/Arguments/ArgumentMatchInfo.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
namespace NSubstitute.Core.Arguments;

public class ArgumentMatchInfo
public class ArgumentMatchInfo(int index, object? argument, IArgumentSpecification specification)
{
public ArgumentMatchInfo(int index, object? argument, IArgumentSpecification specification)
{
Index = index;
_argument = argument;
_specification = specification;
}

private readonly object? _argument;
private readonly IArgumentSpecification _specification;
public int Index { get; }
private readonly object? _argument = argument;
private readonly IArgumentSpecification _specification = specification;
public int Index { get; } = index;

public bool IsMatch => _specification.IsSatisfiedBy(_argument);

Expand Down
9 changes: 2 additions & 7 deletions src/NSubstitute/Core/Arguments/ArgumentMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,9 @@ public static class ArgumentMatcher
return ref new DefaultValueContainer<T>().Value;
}

private class GenericToNonGenericMatcherProxy<T> : IArgumentMatcher
private class GenericToNonGenericMatcherProxy<T>(IArgumentMatcher<T> matcher) : IArgumentMatcher
{
protected readonly IArgumentMatcher<T> _matcher;

public GenericToNonGenericMatcherProxy(IArgumentMatcher<T> matcher)
{
_matcher = matcher;
}
protected readonly IArgumentMatcher<T> _matcher = matcher;

public bool IsSatisfiedBy(object? argument) => _matcher.IsSatisfiedBy((T?)argument!);
}
Expand Down
30 changes: 10 additions & 20 deletions src/NSubstitute/Core/Arguments/ArgumentSpecification.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
namespace NSubstitute.Core.Arguments;

public class ArgumentSpecification : IArgumentSpecification
public class ArgumentSpecification(Type forType, IArgumentMatcher matcher, Action<object?> action) : IArgumentSpecification
{
private static readonly Action<object?> NoOpAction = _ => { };

private readonly IArgumentMatcher _matcher;
private readonly Action<object?> _action;
public Type ForType { get; }
public bool HasAction => _action != NoOpAction;
public Type ForType { get; } = forType;
public bool HasAction => action != NoOpAction;

public ArgumentSpecification(Type forType, IArgumentMatcher matcher) : this(forType, matcher, NoOpAction) { }

public ArgumentSpecification(Type forType, IArgumentMatcher matcher, Action<object?> action)
{
ForType = forType;
_matcher = matcher;
_action = action;
}

public bool IsSatisfiedBy(object? argument)
{
if (!IsCompatibleWith(argument))
Expand All @@ -27,7 +17,7 @@ public bool IsSatisfiedBy(object? argument)

try
{
return _matcher.IsSatisfiedBy(argument);
return matcher.IsSatisfiedBy(argument);
}
catch
{
Expand All @@ -42,7 +32,7 @@ public string DescribeNonMatch(object? argument)
return GetIncompatibleTypeMessage(argument);
}

return _matcher is IDescribeNonMatches describe
return matcher is IDescribeNonMatches describe
? describe.DescribeFor(argument)
: string.Empty;
}
Expand All @@ -51,12 +41,12 @@ public string FormatArgument(object? argument)
{
var isSatisfiedByArg = IsSatisfiedBy(argument);

return _matcher is IArgumentFormatter matcherFormatter
return matcher is IArgumentFormatter matcherFormatter
? matcherFormatter.Format(argument, highlight: !isSatisfiedByArg)
: ArgumentFormatter.Default.Format(argument, highlight: !isSatisfiedByArg);
}

public override string ToString() => _matcher.ToString() ?? string.Empty;
public override string ToString() => matcher.ToString() ?? string.Empty;

public IArgumentSpecification CreateCopyMatchingAnyArgOfType(Type requiredType)
{
Expand All @@ -65,19 +55,19 @@ public IArgumentSpecification CreateCopyMatchingAnyArgOfType(Type requiredType)
return new ArgumentSpecification(
requiredType,
new AnyArgumentMatcher(requiredType),
_action == NoOpAction ? NoOpAction : RunActionIfTypeIsCompatible);
action == NoOpAction ? NoOpAction : RunActionIfTypeIsCompatible);
}

public void RunAction(object? argument)
{
_action(argument);
action(argument);
}

private void RunActionIfTypeIsCompatible(object? argument)
{
if (argument.IsCompatibleWith(ForType))
{
_action(argument);
action(argument);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
namespace NSubstitute.Core.Arguments;

public class ArgumentSpecificationCompatibilityTester : IArgumentSpecificationCompatibilityTester
public class ArgumentSpecificationCompatibilityTester(IDefaultChecker defaultChecker) : IArgumentSpecificationCompatibilityTester
{
private readonly IDefaultChecker _defaultChecker;

public ArgumentSpecificationCompatibilityTester(IDefaultChecker defaultChecker)
{
_defaultChecker = defaultChecker;
}

public bool IsSpecificationCompatible(IArgumentSpecification specification, object? argumentValue, Type argumentType)
{
var typeArgSpecIsFor = specification.ForType;
Expand All @@ -18,7 +11,7 @@ public bool IsSpecificationCompatible(IArgumentSpecification specification, obje

private bool IsProvidedArgumentTheOneWeWouldGetUsingAnArgSpecForThisType(object? argument, Type typeArgSpecIsFor)
{
return _defaultChecker.IsDefault(argument, typeArgSpecIsFor);
return defaultChecker.IsDefault(argument, typeArgSpecIsFor);
}

private bool AreTypesCompatible(Type argumentType, Type typeArgSpecIsFor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,9 @@ private IEnumerable<IArgumentSpecification> UnwrapParamsArguments(IEnumerable<ob
return result;
}

private class ParameterInfoFromType : IParameterInfo
private class ParameterInfoFromType(Type parameterType) : IParameterInfo
{
public ParameterInfoFromType(Type parameterType)
{
ParameterType = parameterType;
}

public Type ParameterType { get; }
public Type ParameterType { get; } = parameterType;

public bool IsParams => false;

Expand Down
21 changes: 7 additions & 14 deletions src/NSubstitute/Core/Arguments/ArgumentSpecificationsFactory.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
using System.Reflection;
using NSubstitute.Exceptions;
using NSubstitute.Exceptions;
using System.Reflection;

namespace NSubstitute.Core.Arguments;

public class ArgumentSpecificationsFactory : IArgumentSpecificationsFactory
public class ArgumentSpecificationsFactory(
IArgumentSpecificationFactory argumentSpecificationFactory,
ISuppliedArgumentSpecificationsFactory suppliedArgumentSpecificationsFactory) : IArgumentSpecificationsFactory
{
private readonly IArgumentSpecificationFactory _argumentSpecificationFactory;
private readonly ISuppliedArgumentSpecificationsFactory _suppliedArgumentSpecificationsFactory;

public ArgumentSpecificationsFactory(IArgumentSpecificationFactory argumentSpecificationFactory, ISuppliedArgumentSpecificationsFactory suppliedArgumentSpecificationsFactory)
{
_argumentSpecificationFactory = argumentSpecificationFactory;
_suppliedArgumentSpecificationsFactory = suppliedArgumentSpecificationsFactory;
}

public IEnumerable<IArgumentSpecification> Create(IList<IArgumentSpecification> argumentSpecs, object?[] arguments, IParameterInfo[] parameterInfos, MethodInfo methodInfo, MatchArgs matchArgs)
{
var suppliedArgumentSpecifications = _suppliedArgumentSpecificationsFactory.Create(argumentSpecs);
var suppliedArgumentSpecifications = suppliedArgumentSpecificationsFactory.Create(argumentSpecs);

var result = new List<IArgumentSpecification>();
for (var i = 0; i < arguments.Length; i++)
Expand All @@ -26,7 +19,7 @@ public IEnumerable<IArgumentSpecification> Create(IList<IArgumentSpecification>

try
{
result.Add(_argumentSpecificationFactory.Create(arg, paramInfo, suppliedArgumentSpecifications));
result.Add(argumentSpecificationFactory.Create(arg, paramInfo, suppliedArgumentSpecifications));
}
catch (AmbiguousArgumentsException ex) when (ex.ContainsDefaultMessage)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,9 @@

namespace NSubstitute.Core.Arguments;

public class ArrayContentsArgumentMatcher : IArgumentMatcher, IArgumentFormatter
public class ArrayContentsArgumentMatcher(IEnumerable<IArgumentSpecification> argumentSpecifications) : IArgumentMatcher, IArgumentFormatter
{
private readonly IArgumentSpecification[] _argumentSpecifications;

public ArrayContentsArgumentMatcher(IEnumerable<IArgumentSpecification> argumentSpecifications)
{
_argumentSpecifications = argumentSpecifications.ToArray();
}
private readonly IArgumentSpecification[] _argumentSpecifications = argumentSpecifications.ToArray();

public bool IsSatisfiedBy(object? argument)
{
Expand Down
11 changes: 2 additions & 9 deletions src/NSubstitute/Core/Arguments/DefaultChecker.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
namespace NSubstitute.Core.Arguments;

public class DefaultChecker : IDefaultChecker
public class DefaultChecker(IDefaultForType defaultForType) : IDefaultChecker
{
private readonly IDefaultForType _defaultForType;

public DefaultChecker(IDefaultForType defaultForType)
{
_defaultForType = defaultForType;
}

public bool IsDefault(object? value, Type forType)
{
return EqualityComparer<object>.Default.Equals(value, _defaultForType.GetDefaultFor(forType));
return EqualityComparer<object>.Default.Equals(value, defaultForType.GetDefaultFor(forType));
}
}
13 changes: 3 additions & 10 deletions src/NSubstitute/Core/Arguments/EqualsArgumentMatcher.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
namespace NSubstitute.Core.Arguments;

public class EqualsArgumentMatcher : IArgumentMatcher
public class EqualsArgumentMatcher(object? value) : IArgumentMatcher
{
private readonly object? _value;
public override string ToString() => ArgumentFormatter.Default.Format(value, false);

public EqualsArgumentMatcher(object? value)
{
_value = value;
}

public override string ToString() => ArgumentFormatter.Default.Format(_value, false);

public bool IsSatisfiedBy(object? argument) => EqualityComparer<object>.Default.Equals(_value, argument);
public bool IsSatisfiedBy(object? argument) => EqualityComparer<object>.Default.Equals(value, argument);
}
Loading

0 comments on commit ee276f3

Please sign in to comment.