Skip to content

Commit

Permalink
Feature: allow access to MethodInfo from CallInfo
Browse files Browse the repository at this point in the history
  • Loading branch information
JMolenkamp committed Jan 29, 2025
1 parent dfef728 commit 063db99
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 2 deletions.
5 changes: 4 additions & 1 deletion src/NSubstitute/Core/CallInfo.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using NSubstitute.Exceptions;

// Disable nullability for entry-point API
#nullable disable annotations

namespace NSubstitute.Core;

public class CallInfo(Argument[] callArguments)
public class CallInfo(Argument[] callArguments, MethodInfo methodInfo)
{

/// <summary>
Expand All @@ -25,6 +26,8 @@ public object this[int index]
}
}

public MethodInfo MethodInfo => methodInfo;

private void EnsureArgIsSettable(Argument argument, int index, object value)
{
if (!argument.IsByRef)
Expand Down
2 changes: 1 addition & 1 deletion src/NSubstitute/Core/CallInfoFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public class CallInfoFactory : ICallInfoFactory
public CallInfo Create(ICall call)
{
var arguments = GetArgumentsFromCall(call);
return new CallInfo(arguments);
return new CallInfo(arguments, call.GetMethodInfo());
}

private static Argument[] GetArgumentsFromCall(ICall call)
Expand Down
33 changes: 33 additions & 0 deletions tests/NSubstitute.Acceptance.Specs/GenericArguments.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections;
using System.Globalization;
using System.Reflection;
using NUnit.Framework;

namespace NSubstitute.Acceptance.Specs;
Expand All @@ -11,6 +12,7 @@ public interface ISomethingWithGenerics
{
void SomeAction<TState>(int level, TState state);
string SomeFunction<TState>(int level, TState state);
ICollection<TState> SomeFunction<TState>(int level);
void SomeActionWithGenericConstraints<TState>(int level, TState state) where TState : IEnumerable<int>;
string SomeFunctionWithGenericConstraints<TState>(int level, TState state) where TState : IEnumerable<int>;
}
Expand Down Expand Up @@ -131,4 +133,35 @@ public void Is_matcher_works_with_AnyType_and_constraints()

Assert.That(result, Is.EqualTo("matched"));
}

[Test]
public void Callback_allows_access_to_method_call()
{
static ICollection<T> CreateSubstitute<T>(int count)
{
ICollection<T> substitute = Substitute.For<ICollection<T>>();
substitute.Count.Returns(count);
return substitute;
}

MethodInfo methodInfo = typeof(GenericArguments)
.GetMethods(BindingFlags.Static | BindingFlags.NonPublic)
.Single(x
=> x.Name.Contains(nameof(CreateSubstitute))
&& x.Name.Contains(nameof(Callback_allows_access_to_method_call)));

ISomethingWithGenerics something = Substitute.For<ISomethingWithGenerics>();
something
.SomeFunction<Arg.AnyType>(Arg.Any<int>())
.Returns(x =>
{
Type argumentType = x.MethodInfo.GetGenericArguments()[0];
MethodInfo method = methodInfo.MakeGenericMethod(argumentType);
return method.Invoke(null, [x.Arg<int>()]);
});

ICollection<int> result = something.SomeFunction<int>(7);

Assert.That(result.Count, Is.EqualTo(7));
}
}

0 comments on commit 063db99

Please sign in to comment.