forked from nsubstitute/NSubstitute
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve output for expected argument matchers
- Add IDescribeSpecification to allow custom arg matchers to provide custom output for "expected to receive" entries. - Fallback to ToString when IDescribeSpecification not implemented. - Update code comment docs accordingly. Relates to nsubstitute#796.
- Loading branch information
Showing
7 changed files
with
162 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
src/NSubstitute/Core/Arguments/ArgumentSpecification.cs.orig
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
namespace NSubstitute.Core.Arguments; | ||
|
||
public class ArgumentSpecification(Type forType, IArgumentMatcher matcher, Action<object?> action) : IArgumentSpecification | ||
{ | ||
private static readonly Action<object?> NoOpAction = _ => { }; | ||
public Type ForType { get; } = forType; | ||
public bool HasAction => action != NoOpAction; | ||
|
||
public ArgumentSpecification(Type forType, IArgumentMatcher matcher) : this(forType, matcher, NoOpAction) { } | ||
|
||
public bool IsSatisfiedBy(object? argument) | ||
{ | ||
if (!IsCompatibleWith(argument)) | ||
{ | ||
return false; | ||
} | ||
|
||
try | ||
{ | ||
return matcher.IsSatisfiedBy(argument); | ||
} | ||
catch | ||
{ | ||
return false; | ||
} | ||
} | ||
|
||
public string DescribeNonMatch(object? argument) | ||
{ | ||
if (!IsCompatibleWith(argument)) | ||
{ | ||
return GetIncompatibleTypeMessage(argument); | ||
} | ||
|
||
return matcher is IDescribeNonMatches describe | ||
? describe.DescribeFor(argument) | ||
: string.Empty; | ||
} | ||
|
||
public string FormatArgument(object? argument) | ||
{ | ||
var isSatisfiedByArg = IsSatisfiedBy(argument); | ||
|
||
return matcher is IArgumentFormatter matcherFormatter | ||
? matcherFormatter.Format(argument, highlight: !isSatisfiedByArg) | ||
: ArgumentFormatter.Default.Format(argument, highlight: !isSatisfiedByArg); | ||
} | ||
|
||
<<<<<<< HEAD | ||
public override string ToString() => matcher.ToString() ?? string.Empty; | ||
======= | ||
public override string ToString() => | ||
_matcher is IDescribeSpecification describe | ||
? describe.DescribeSpecification() | ||
: _matcher.ToString() ?? string.Empty; | ||
>>>>>>> aa3cd12 (Apply review comments) | ||
|
||
public IArgumentSpecification CreateCopyMatchingAnyArgOfType(Type requiredType) | ||
{ | ||
// Don't pass RunActionIfTypeIsCompatible method if no action is present. | ||
// Otherwise, unnecessary closure will keep reference to this and will keep it alive. | ||
return new ArgumentSpecification( | ||
requiredType, | ||
new AnyArgumentMatcher(requiredType), | ||
action == NoOpAction ? NoOpAction : RunActionIfTypeIsCompatible); | ||
} | ||
|
||
public void RunAction(object? argument) | ||
{ | ||
action(argument); | ||
} | ||
|
||
private void RunActionIfTypeIsCompatible(object? argument) | ||
{ | ||
if (argument.IsCompatibleWith(ForType)) | ||
{ | ||
action(argument); | ||
} | ||
} | ||
|
||
private bool IsCompatibleWith(object? argument) => argument.IsCompatibleWith(ForType); | ||
|
||
private string GetIncompatibleTypeMessage(object? argument) | ||
{ | ||
var argumentType = argument == null ? typeof(object) : argument.GetType(); | ||
return $"Expected an argument compatible with type '{ForType}'. Actual type was '{argumentType}'."; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
namespace NSubstitute.Core; | ||
|
||
/// <summary> | ||
/// A type that can describe the required conditions to meet a specification. | ||
/// Use in conjunction with <see cref="NSubstitute.Core.Arguments.IArgumentMatcher"/> to provide information about | ||
/// what it requires to match an argument. | ||
/// </summary> | ||
public interface IDescribeSpecification | ||
{ | ||
|
||
/// <summary> | ||
/// A concise description of the conditions required to match this specification. | ||
/// </summary> | ||
/// <returns></returns> | ||
string DescribeSpecification(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters