Skip to content

Commit

Permalink
Solve DoForAny issue with an overload.
Browse files Browse the repository at this point in the history
  • Loading branch information
icalvo committed Jun 5, 2023
1 parent 93e2524 commit ce6793b
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 33 deletions.
26 changes: 10 additions & 16 deletions src/NSubstitute/Arg.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System;
using System.Linq.Expressions;
using NSubstitute.Core;
using NSubstitute.Core.Arguments;
using NSubstitute.Exceptions;

// Disable nullability for client API, so it does not affect clients.
#nullable disable annotations
#pragma warning disable CS1574
#pragma warning disable CS0419

namespace NSubstitute
{
Expand All @@ -14,7 +14,9 @@ namespace NSubstitute
/// </summary>
public static class Arg
{
public class AnyType { }
public class AnyType
{
}

/// <summary>
/// Match any argument value compatible with type <typeparamref name="T"/>.
Expand Down Expand Up @@ -96,20 +98,14 @@ public static ref TDelegate InvokeDelegate<TDelegate>(params object[] arguments)
/// </summary>
public static ref T Do<T>(Action<T> useArgument)
{
if (typeof(T) == typeof(AnyType))
{
SubstitutionContext.Current.ThreadContext.DequeueAllArgumentSpecifications();
throw new DoAnyTypeException();
}

return ref ArgumentMatcher.Enqueue<T>(new AnyArgumentMatcher(typeof(T)), x => useArgument((T) x!));
}

/// <summary>
/// Capture any argument and use it to call the <paramref name="useArgument"/> function
/// Capture any argument compatible with type <typeparamref name="T"/> and use it to call the <paramref name="useArgument"/> function
/// whenever a matching call is made to the substitute.
/// </summary>
public static ref AnyType DoForAny(Action<object> useArgument)
public static ref AnyType Do<T>(Action<object> useArgument) where T : AnyType
{
return ref ArgumentMatcher.Enqueue<AnyType>(new AnyArgumentMatcher(typeof(AnyType)), x => useArgument(x!));
}
Expand Down Expand Up @@ -194,15 +190,13 @@ public static class Compat
/// This is provided for compatibility with older compilers --
/// if possible use <see cref="Arg.Do{T}" /> instead.
/// </summary>
public static T Do<T>(Action<T> useArgument) => Arg.Do(useArgument);
public static T Do<T>(Action<T> useArgument) => Arg.Do<T>(useArgument);

/// <summary>
/// Capture any argument and use it to call the <paramref name="useArgument"/> function
/// Capture any argument compatible with type <typeparamref name="T"/> and use it to call the <paramref name="useArgument"/> function
/// whenever a matching call is made to the substitute.
/// This is provided for compatibility with older compilers --
/// if possible use <see cref="Arg.DoForAny" /> instead.
/// </summary>
public static AnyType DoForAny(Action<object> useArgument) => Arg.DoForAny(useArgument);
public static AnyType Do<T>(Action<object> useArgument) where T : AnyType => Arg.Do<T>(useArgument);
}

private static Action<object> InvokeDelegateAction(params object[] arguments)
Expand Down
8 changes: 4 additions & 4 deletions src/NSubstitute/Compatibility/CompatArg.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

// Disable nullability for client API, so it does not affect clients.
#nullable disable annotations
#pragma warning disable CS1574
#pragma warning disable CS0419

namespace NSubstitute.Compatibility
{
Expand Down Expand Up @@ -100,11 +102,9 @@ private CompatArg() { }
public T Do<T>(Action<T> useArgument) => Arg.Do(useArgument);

/// <summary>
/// Capture any argument and use it to call the <paramref name="useArgument"/> function
/// Capture any argument compatible with type <typeparamref name="T"/> and use it to call the <paramref name="useArgument"/> function
/// whenever a matching call is made to the substitute.
/// This is provided for compatibility with older compilers --
/// if possible use <see cref="Arg.DoForAny" /> instead.
/// </summary>
public static Arg.AnyType DoForAny(Action<object> useArgument) => Arg.DoForAny(useArgument);
public static Arg.AnyType Do<T>(Action<object> useArgument) where T : Arg.AnyType => Arg.Do<T>(useArgument);
}
}
18 changes: 5 additions & 13 deletions tests/NSubstitute.Acceptance.Specs/GenericArguments.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using NSubstitute.Exceptions;
using System;
using System.Collections.Generic;
using NSubstitute.Exceptions;
using NUnit.Framework;

namespace NSubstitute.Acceptance.Specs;
Expand All @@ -17,9 +19,8 @@ public void Return_result_for_any_argument()
string argDoResult = null;
int? whenDoResult = null;
bool whenDoCalled = false;

ISomethingWithGenerics something = Substitute.For<ISomethingWithGenerics>();
something.Log(Arg.Any<int>(), Arg.DoForAny(a => argDoResult = a.ToString()));
something.Log(Arg.Any<int>(), Arg.Do<Arg.AnyType>(a => argDoResult = ">>" + ((int)a).ToString("P")));
something
.When(substitute => substitute.Log(Arg.Any<int>(), Arg.Any<Arg.AnyType>()))
.Do(info =>
Expand All @@ -33,16 +34,7 @@ public void Return_result_for_any_argument()
something.Received().Log(Arg.Any<int>(), Arg.Any<Arg.AnyType>());
something.Received().Log(7, 3409);
Assert.That(whenDoCalled, Is.True);
Assert.That(argDoResult, Is.EqualTo("3409"));
Assert.That(argDoResult, Is.EqualTo(">>340 900.00 %"));
Assert.That(whenDoResult, Is.EqualTo(3409));
}

[Test]
public void Throw_with_Do_AnyType()
{
ISomethingWithGenerics something = Substitute.For<ISomethingWithGenerics>();

Assert.Throws<DoAnyTypeException>(() =>
something.Log(Arg.Any<int>(), Arg.Do<Arg.AnyType>(a => _ = a.ToString())));
}
}

0 comments on commit ce6793b

Please sign in to comment.