Add extensibility point for custom auto value providers

More precise set of changes:

- Ensure that specification evaluates original argument values,
  because they could be modified during call dispatch.

- Ensure that original arguments are used to check whether
  current call meets particular specification.

- Use own results cache for AutoValues route handler.
  That is needed to ensure that AutoValues priority isn't increased.

  Otherwise, once handler invoked for the first time,
  it's "memory" will have same priority as user configured results.
  As outcome, custom handlers, returns for type, etc will not be invoked.
This commit is contained in:
Alex Povar 2016-11-07 19:33:14 +02:00
Родитель 10fa6bcce8
Коммит db8c2e0853
20 изменённых файлов: 485 добавлений и 21 удалений

Просмотреть файл

@ -112,6 +112,9 @@
<Compile Include="..\NSubstitute.Acceptance.Specs\ClearSubstitute.cs">
<Link>ClearSubstitute.cs</Link>
</Compile>
<Compile Include="..\NSubstitute.Acceptance.Specs\CustomHandlersSpecs.cs">
<Link>CustomHandlersSpecs.cs</Link>
</Compile>
<Compile Include="..\NSubstitute.Acceptance.Specs\DynamicCalls.cs">
<Link>DynamicCalls.cs</Link>
</Compile>

Просмотреть файл

@ -0,0 +1,236 @@
using System;
using System.Collections.Generic;
using NSubstitute.Core;
using NUnit.Framework;
namespace NSubstitute.Acceptance.Specs
{
[TestFixture]
public class CustomHandlersSpecs
{
[Test]
public void Value_from_custom_handler_is_returned()
{
//arrange
var source = Substitute.For<IValueSource>();
var router = SubstitutionContext.Current.GetCallRouterFor(source);
router.RegisterCustomCallHandlerFactory(state =>
new ActionHandler(
_ => RouteAction.Return("42")));
//act
var result = source.GetValue();
//assert
Assert.That(result, Is.EqualTo("42"));
}
[Test]
public void Value_from_custom_handler_is_returned_for_setup_after_invocation()
{
//arrange
var source = Substitute.For<IValueSource>();
var router = SubstitutionContext.Current.GetCallRouterFor(source);
//invoke it before registering handler
source.GetValue();
router.RegisterCustomCallHandlerFactory(state =>
new ActionHandler(
_ => RouteAction.Return("42")));
//act
var result = source.GetValue();
//assert
Assert.That(result, Is.EqualTo("42"));
}
[Test]
public void Custom_handler_is_called_for_each_time()
{
//arrange
var source = Substitute.For<IValueSource>();
var router = SubstitutionContext.Current.GetCallRouterFor(source);
var values = new Queue<string>(new[] { "42", "10" });
router.RegisterCustomCallHandlerFactory(state =>
new ActionHandler(
_ => RouteAction.Return(values.Dequeue())));
//act
var result = source.GetValue();
result = source.GetValue();
//assert
Assert.That(result, Is.EqualTo("10"));
}
[Test]
public void Configured_call_has_more_priority_than_custom_handler()
{
//arrange
var source = Substitute.For<IValueSource>();
var router = SubstitutionContext.Current.GetCallRouterFor(source);
router.RegisterCustomCallHandlerFactory(state =>
new ActionHandler(
_ => RouteAction.Return("xxx")));
source.GetValue().Returns("42");
//act
var result = source.GetValue();
//assert
Assert.That(result, Is.EqualTo("42"));
}
[Test]
public void Updated_ref_parameter_doesnt_affect_call_specification()
{
//arrange
var source = Substitute.For<IValueSource>();
var router = SubstitutionContext.Current.GetCallRouterFor(source);
//Configure our handler to update "ref" argument value
router.RegisterCustomCallHandlerFactory(state =>
new ActionHandler(
call =>
{
if (call.GetMethodInfo().Name != nameof(IValueSource.GetValueWithRef))
return RouteAction.Continue();
var args = call.GetArguments();
args[0] = "refArg";
return RouteAction.Return("xxx");
}));
string refValue = "ref";
source.GetValueWithRef(ref refValue).Returns("42");
//act
refValue = "ref";
var result = source.GetValueWithRef(ref refValue);
//assert
Assert.That(result, Is.EqualTo("42"));
}
[Test]
public void Set_out_parameter_doesnt_affect_call_specification()
{
var source = Substitute.For<IValueSource>();
var router = SubstitutionContext.Current.GetCallRouterFor(source);
//Configure our handler to update "out" argument value
router.RegisterCustomCallHandlerFactory(state =>
new ActionHandler(
call =>
{
if (call.GetMethodInfo().Name != nameof(IValueSource.GetValueWithOut))
return RouteAction.Continue();
var args = call.GetArguments();
args[0] = "outArg";
return RouteAction.Return("xxx");
}));
string outArg;
source.GetValueWithOut(out outArg).Returns("42");
//act
string otherOutArg;
var result = source.GetValueWithOut(out otherOutArg);
//assert
Assert.That(result, Is.EqualTo("42"));
}
[Test]
public void Is_not_called_for_specifying_call()
{
//arrange
var source = Substitute.For<IValueSource>();
var router = SubstitutionContext.Current.GetCallRouterFor(source);
bool wasInvoked = false;
router.RegisterCustomCallHandlerFactory(state =>
new ActionHandler(_ =>
{
wasInvoked = true;
return RouteAction.Continue();
}));
//act
source.MethodWithArgs(Arg.Any<string>(), Arg.Is("42")).Returns("");
//assert
Assert.That(wasInvoked, Is.False);
}
[Test]
public void Auto_value_is_returned_if_skipped()
{
//arrange
var source = Substitute.For<IValueSource>();
var router = SubstitutionContext.Current.GetCallRouterFor(source);
router.RegisterCustomCallHandlerFactory(state =>
new ActionHandler(_ => RouteAction.Continue()));
//act
var result = source.GetValue();
//assert
Assert.That(result, Is.Not.Null);
}
[Test]
public void First_added_handler_has_precedence()
{
//arrange
var source = Substitute.For<IValueSource>();
var router = SubstitutionContext.Current.GetCallRouterFor(source);
router.RegisterCustomCallHandlerFactory(state =>
new ActionHandler(
_ => RouteAction.Return("42")));
router.RegisterCustomCallHandlerFactory(state =>
new ActionHandler(
_ => RouteAction.Return("10")));
//act
var result = source.GetValue();
//assert
Assert.That(result, Is.EqualTo("42"));
}
public interface IValueSource
{
string GetValue();
string GetValueWithRef(ref string arg1);
string GetValueWithOut(out string arg1);
string MethodWithArgs(string arg1, string arg2);
}
private class ActionHandler : ICallHandler
{
private readonly Func<ICall, RouteAction> _handler;
public ActionHandler(Func<ICall, RouteAction> handler)
{
_handler = handler;
}
public RouteAction Handle(ICall call) => _handler.Invoke(call);
}
}
}

Просмотреть файл

@ -1,3 +1,4 @@
using System;
using NSubstitute.Exceptions;
using NUnit.Framework;
@ -9,7 +10,7 @@ namespace NSubstitute.Acceptance.Specs
{
bool TryRef(ref int number);
bool TryGet(string key, out string value);
string Get(string key);
string GetWithRef(ref string key);
string LookupByObject(ref object obj);
}
@ -138,6 +139,116 @@ namespace NSubstitute.Acceptance.Specs
Assert.That(something.GetValue("diff key"), Is.EqualTo("none"));
}
[Test]
public void Modified_ref_arg_should_not_affect_specification_match()
{
//arrange
var lookup = Substitute.For<ILookupStrings>();
int magicInt = 42;
lookup.TryRef(ref magicInt).Returns(true);
int anyInt = Arg.Any<int>();
lookup.When(l => l.TryRef(ref anyInt)).Do(c => { c[0] = 100; });
//act
magicInt = 42;
var result = lookup.TryRef(ref magicInt);
//assert
Assert.That(result, Is.True);
Assert.That(magicInt, Is.EqualTo(100));
}
[Test]
public void Modified_out_arg_should_not_affect_specification_match()
{
//arrange
var lookup = Substitute.For<ILookupStrings>();
string key = "key";
//Configure to have result for out parameter
string retValue;
lookup.TryGet(key, out retValue).Returns(true);
//Set parameter in When/Do to always initialize out parameter
string retValueTmp;
lookup.When(l => l.TryGet(key, out retValueTmp)).Do(c => { c[1] = "42"; });
//act
//Check whether our configuration is still actual
string actualRet;
var result = lookup.TryGet(key, out actualRet);
//assert
Assert.That(result, Is.True);
Assert.That(actualRet, Is.EqualTo("42"));
}
[Test]
public void Configuration_for_already_configured_call_works()
{
//arrange
var lookup = Substitute.For<ILookupStrings>();
string anyRef = Arg.Any<string>();
lookup.GetWithRef(ref anyRef).Returns(c => { c[0] = "42"; return "result"; });
//act
string otherKey = "xxx";
lookup.GetWithRef(ref otherKey).Returns("100");
otherKey = "xxx";
var actualResult = lookup.GetWithRef(ref otherKey);
//assert
Assert.That(actualResult, Is.EqualTo("100"));
Assert.That(otherKey, Is.EqualTo("xxx"));
}
[Test]
public void Configuration_for_modified_args_works()
{
//arrange
var lookup = Substitute.For<ILookupStrings>();
string anyRef = Arg.Any<string>();
lookup.When(l => l.GetWithRef(ref anyRef)).Do(c => { c[0] = "42"; });
//act
string specRef = "xxx";
lookup.GetWithRef(ref specRef).Returns("100");
specRef = "xxx";
var result = lookup.GetWithRef(ref specRef);
//assert
Assert.That(result, Is.EqualTo("100"));
Assert.That(specRef, Is.EqualTo("42"));
}
[Test]
public void Exception_message_displays_original_values()
{
//arrange
var lookup = Substitute.For<ILookupStrings>();
string anyRef = Arg.Any<string>();
lookup.When(l => l.GetWithRef(ref anyRef)).Do(c => { c[0] = "42"; });
//act
string key = "12345";
lookup.GetWithRef(ref key);
//assert
//Assert that message is like "Expected '98765', but received '12345'".
key = "98765";
var exception = Assert.Throws<ReceivedCallsException>(() => lookup.Received().GetWithRef(ref key));
StringAssert.Contains("98765", exception.Message);
StringAssert.Contains("12345", exception.Message);
}
private class Something
{
private readonly ILookupStrings _lookup;

Просмотреть файл

@ -294,6 +294,9 @@
<Compile Include="..\NSubstitute\Core\ConfiguredCall.cs">
<Link>Core\ConfiguredCall.cs</Link>
</Compile>
<Compile Include="..\NSubstitute\Core\CustomHandlers.cs">
<Link>Core\CustomHandlers.cs</Link>
</Compile>
<Compile Include="..\NSubstitute\Core\DefaultForType.cs">
<Link>Core\DefaultForType.cs</Link>
</Compile>
@ -360,6 +363,9 @@
<Compile Include="..\NSubstitute\Core\IConfigureCall.cs">
<Link>Core\IConfigureCall.cs</Link>
</Compile>
<Compile Include="..\NSubstitute\Core\ICustomHandlers.cs">
<Link>Core\ICustomHandlers.cs</Link>
</Compile>
<Compile Include="..\NSubstitute\Core\IDefaultForType.cs">
<Link>Core\IDefaultForType.cs</Link>
</Compile>
@ -651,6 +657,9 @@
<Compile Include="..\NSubstitute\Routing\Handlers\ReturnFromBaseIfRequired.cs">
<Link>Routing\Handlers\ReturnFromBaseIfRequired.cs</Link>
</Compile>
<Compile Include="..\NSubstitute\Routing\Handlers\ReturnFromCustomHandlers.cs">
<Link>Routing\Handlers\ReturnFromCustomHandlers.cs</Link>
</Compile>
<Compile Include="..\NSubstitute\Routing\Handlers\ReturnResultForTypeHandler.cs">
<Link>Routing\Handlers\ReturnResultForTypeHandler.cs</Link>
</Compile>

Просмотреть файл

@ -86,6 +86,7 @@ namespace NSubstitute.Specs
var call = mock<ICall>();
call.stub(x => x.GetMethodInfo()).Return(methodInfo);
call.stub(x => x.GetArguments()).Return(arguments);
call.stub(x => x.GetOriginalArguments()).Return(arguments);
call.stub(x => x.GetArgumentSpecifications()).Return(mock<IList<IArgumentSpecification>>());
return call;
}

Просмотреть файл

@ -11,6 +11,11 @@ namespace NSubstitute.Specs.Infrastructure
{
return new ConfiguredCall(x => { });
}
public void RegisterCustomCallHandlerFactory(CallHandlerFactory factory)
{
}
public void Clear(ClearOptions clear) { }
public IEnumerable<ICall> ReceivedCalls() { return new ICall[0]; }

Просмотреть файл

@ -16,7 +16,9 @@ namespace NSubstitute.Specs.Routing.Handlers
protected IAutoValueProvider _secondAutoValueProvider;
protected RouteAction _result;
protected ICall _call;
protected IConfigureCall ConfigureCall;
protected ICallResults _callResults;
protected ICallSpecification _callSpecification;
protected ICallSpecificationFactory _callSpecificationFactory;
public override void Because()
{
@ -26,16 +28,19 @@ namespace NSubstitute.Specs.Routing.Handlers
public override void Context()
{
base.Context();
ConfigureCall = mock<IConfigureCall>();
_call = mock<ICall>();
_call.stub(x => x.GetReturnType()).Return(_type);
_callResults = mock<ICallResults>();
_callSpecification = mock<ICallSpecification>();
_callSpecificationFactory = mock<ICallSpecificationFactory>();
_callSpecificationFactory.stub(x => x.CreateFrom(_call, MatchArgs.AsSpecifiedInCall)).Return(_callSpecification);
_firstAutoValueProvider = mock<IAutoValueProvider>();
_secondAutoValueProvider = mock<IAutoValueProvider>();
}
public ReturnAutoValue CreateReturnAutoValue(AutoValueBehaviour autoValueBehaviour)
{
return new ReturnAutoValue(autoValueBehaviour, new[] {_firstAutoValueProvider, _secondAutoValueProvider}, ConfigureCall);
return new ReturnAutoValue(autoValueBehaviour, new[] {_firstAutoValueProvider, _secondAutoValueProvider}, _callResults, _callSpecificationFactory);
}
}
@ -52,7 +57,7 @@ namespace NSubstitute.Specs.Routing.Handlers
[Test]
public void Should_set_auto_value_as_value_to_return_for_subsequent_calls()
{
ConfigureCall.received(x => x.SetResultForCall(It.Is(_call), It.Matches<IReturn>(arg => arg.ReturnFor(null) == _autoValue), It.Is(MatchArgs.AsSpecifiedInCall)));
_callResults.received(x => x.SetResult(It.Is(_callSpecification), It.Matches<IReturn>(arg => arg.ReturnFor(null) == _autoValue)));
}
public override void Context()
@ -95,7 +100,7 @@ namespace NSubstitute.Specs.Routing.Handlers
[Test]
public void Should_set_auto_value_as_value_to_return_for_subsequent_calls()
{
ConfigureCall.did_not_receive_with_any_args(x => x.SetResultForCall(null, null, null));
_callResults.did_not_receive_with_any_args(x => x.SetResult(null, null));
}
public override void Context()

Просмотреть файл

@ -11,6 +11,7 @@ namespace NSubstitute.Core
{
private readonly MethodInfo _methodInfo;
private readonly object[] _arguments;
private readonly object[] _originalArguments;
private readonly object _target;
private readonly IParameterInfo[] _parameterInfos;
private readonly IList<IArgumentSpecification> _argumentSpecifications;
@ -21,6 +22,7 @@ namespace NSubstitute.Core
{
_methodInfo = methodInfo;
_arguments = arguments;
_originalArguments = arguments.ToArray();
_target = target;
_parameterInfos = GetParameterInfosFrom(_methodInfo);
_argumentSpecifications = argumentSpecsForCall;
@ -31,6 +33,7 @@ namespace NSubstitute.Core
{
_methodInfo = methodInfo;
_arguments = arguments;
_originalArguments = arguments.ToArray();
_target = target;
_parameterInfos = parameterInfos ?? GetParameterInfosFrom(_methodInfo);
_argumentSpecifications = (_parameterInfos.Length == 0) ? EmptyList() : SubstitutionContext.Current.DequeueAllArgumentSpecifications();
@ -92,6 +95,11 @@ namespace NSubstitute.Core
return _arguments;
}
public object[] GetOriginalArguments()
{
return _originalArguments;
}
public object Target()
{
return _target;

Просмотреть файл

@ -95,5 +95,12 @@ namespace NSubstitute.Core
{
_substituteState.ResultsForType.SetResult(type, returnValue);
}
public void RegisterCustomCallHandlerFactory(CallHandlerFactory factory)
{
if (factory == null) throw new ArgumentNullException(nameof(factory));
_substituteState.CustomHandlers.AddCustomHandlerFactory(factory);
}
}
}

Просмотреть файл

@ -73,9 +73,9 @@ namespace NSubstitute.Core
&& a.Name.Equals(b.Name, StringComparison.Ordinal);
}
public IEnumerable<ArgumentMatchInfo> NonMatchingArguments(ICall call)
public IEnumerable<ArgumentMatchInfo> NonMatchingArguments(ICall call)
{
var arguments = call.GetArguments();
var arguments = call.GetOriginalArguments();
return arguments
.Select((arg, index) => new ArgumentMatchInfo(index, arg, _argumentSpecifications[index]))
.Where(x => !x.IsMatch);
@ -89,7 +89,7 @@ namespace NSubstitute.Core
public string Format(ICall call)
{
return CallFormatter.Format(call.GetMethodInfo(), FormatArguments(call.GetArguments()));
return CallFormatter.Format(call.GetMethodInfo(), FormatArguments(call.GetOriginalArguments()));
}
private IEnumerable<string> FormatArguments(IEnumerable<object> arguments)
@ -122,7 +122,7 @@ namespace NSubstitute.Core
private bool HasDifferentNumberOfArguments(ICall call)
{
return _argumentSpecifications.Length != call.GetArguments().Length;
return _argumentSpecifications.Length != call.GetOriginalArguments().Length;
}
}
}

Просмотреть файл

@ -15,7 +15,7 @@ namespace NSubstitute.Core
{
var methodInfo = call.GetMethodInfo();
var argumentSpecs = call.GetArgumentSpecifications();
var arguments = call.GetArguments();
var arguments = call.GetOriginalArguments();
var parameterInfos = call.GetParameterInfos();
var argumentSpecificationsForCall = _argumentSpecificationsFactory.Create(argumentSpecs, arguments, parameterInfos, matchArgs);
return new CallSpecification(methodInfo, argumentSpecificationsForCall);

Просмотреть файл

@ -0,0 +1,22 @@
using System.Collections.Generic;
namespace NSubstitute.Core
{
public class CustomHandlers : ICustomHandlers
{
private readonly List<ICallHandler> _handlers = new List<ICallHandler>();
private readonly ISubstituteState _substituteState;
public IEnumerable<ICallHandler> Handlers => _handlers;
public CustomHandlers(ISubstituteState substituteState)
{
_substituteState = substituteState;
}
public void AddCustomHandlerFactory(CallHandlerFactory factory)
{
_handlers.Add(factory.Invoke(_substituteState));
}
}
}

Просмотреть файл

@ -10,6 +10,7 @@ namespace NSubstitute.Core
Type GetReturnType();
MethodInfo GetMethodInfo();
object[] GetArguments();
object[] GetOriginalArguments();
object Target();
IParameterInfo[] GetParameterInfos();
IList<IArgumentSpecification> GetArgumentSpecifications();

Просмотреть файл

@ -11,6 +11,7 @@ namespace NSubstitute.Core
IEnumerable<ICall> ReceivedCalls();
void SetRoute(Func<ISubstituteState, IRoute> getRoute);
void SetReturnForType(Type type, IReturn returnValue);
void RegisterCustomCallHandlerFactory(CallHandlerFactory factory);
void Clear(ClearOptions clear);
}
}

Просмотреть файл

@ -0,0 +1,15 @@
using System.Collections.Generic;
namespace NSubstitute.Core
{
/// <summary>
/// Factory method which creates <see cref="ICallHandler" /> from the <see cref="ISubstituteState" />.
/// </summary>
public delegate ICallHandler CallHandlerFactory(ISubstituteState substituteState);
public interface ICustomHandlers
{
IEnumerable<ICallHandler> Handlers { get; }
void AddCustomHandlerFactory(CallHandlerFactory factory);
}
}

Просмотреть файл

@ -16,8 +16,10 @@ namespace NSubstitute.Core
IConfigureCall ConfigureCall { get; }
IEventHandlerRegistry EventHandlerRegistry { get; }
IAutoValueProvider[] AutoValueProviders { get; }
ICallResults AutoValuesCallResults { get; }
ICallBaseExclusions CallBaseExclusions { get; }
IResultsForType ResultsForType { get; }
ICustomHandlers CustomHandlers { get; }
void ClearUnusedCallSpecs();
}
}

Просмотреть файл

@ -17,7 +17,9 @@ namespace NSubstitute.Core
public IConfigureCall ConfigureCall { get; private set; }
public IEventHandlerRegistry EventHandlerRegistry { get; private set; }
public IAutoValueProvider[] AutoValueProviders { get; private set; }
public ICallResults AutoValuesCallResults { get; }
public IResultsForType ResultsForType { get; private set; }
public ICustomHandlers CustomHandlers { get; }
public SubstituteState(ISubstitutionContext substitutionContext, SubstituteConfig option)
{
@ -31,13 +33,13 @@ namespace NSubstitute.Core
ReceivedCalls = callStack;
PendingSpecification = new PendingSpecification();
CallResults = new CallResults(callInfoFactory);
AutoValuesCallResults = new CallResults(callInfoFactory);
CallSpecificationFactory = CallSpecificationFactoryFactoryYesThatsRight.CreateCallSpecFactory();
CallActions = new CallActions(callInfoFactory);
CallBaseExclusions = new CallBaseExclusions();
ResultsForType = new ResultsForType(callInfoFactory);
CustomHandlers = new CustomHandlers(this);
var getCallSpec = new GetCallSpec(callStack, PendingSpecification, CallSpecificationFactory, CallActions);
ConfigureCall = new ConfigureCall(CallResults, CallActions, getCallSpec);
EventHandlerRegistry = new EventHandlerRegistry();
AutoValueProviders = new IAutoValueProvider[] {

Просмотреть файл

@ -14,18 +14,25 @@ namespace NSubstitute.Routing.Handlers
public class ReturnAutoValue : ICallHandler
{
private readonly IEnumerable<IAutoValueProvider> _autoValueProviders;
private readonly ICallResults _callResults;
private readonly ICallSpecificationFactory _callSpecificationFactory;
private readonly AutoValueBehaviour _autoValueBehaviour;
private readonly IConfigureCall ConfigureCall;
public ReturnAutoValue(AutoValueBehaviour autoValueBehaviour, IEnumerable<IAutoValueProvider> autoValueProviders, IConfigureCall configureCall)
public ReturnAutoValue(AutoValueBehaviour autoValueBehaviour, IEnumerable<IAutoValueProvider> autoValueProviders, ICallResults callResults, ICallSpecificationFactory callSpecificationFactory)
{
_autoValueProviders = autoValueProviders;
ConfigureCall = configureCall;
_callResults = callResults;
_callSpecificationFactory = callSpecificationFactory;
_autoValueBehaviour = autoValueBehaviour;
}
public RouteAction Handle(ICall call)
{
if (_callResults.HasResultFor(call))
{
return RouteAction.Return(_callResults.GetResult(call));
}
var type = call.GetReturnType();
var compatibleProviders = _autoValueProviders.Where(x => x.CanProvideValueFor(type)).FirstOrNothing();
return compatibleProviders.Fold(
@ -40,7 +47,8 @@ namespace NSubstitute.Routing.Handlers
var valueToReturn = provider.GetValue(type);
if (_autoValueBehaviour == AutoValueBehaviour.UseValueForSubsequentCalls)
{
ConfigureCall.SetResultForCall(call, new ReturnValue(valueToReturn), MatchArgs.AsSpecifiedInCall);
var spec = _callSpecificationFactory.CreateFrom(call, MatchArgs.AsSpecifiedInCall);
_callResults.SetResult(spec, new ReturnValue(valueToReturn));
}
return RouteAction.Return(valueToReturn);
};

Просмотреть файл

@ -0,0 +1,27 @@
using NSubstitute.Core;
namespace NSubstitute.Routing.Handlers
{
public class ReturnFromCustomHandlers : ICallHandler
{
private readonly ICustomHandlers _customHandlers;
public ReturnFromCustomHandlers(ICustomHandlers customHandlers)
{
_customHandlers = customHandlers;
}
public RouteAction Handle(ICall call)
{
foreach (var handler in _customHandlers.Handlers)
{
var result = handler.Handle(call);
if (result.HasReturnValue)
{
return result;
}
}
return RouteAction.Continue();
}
}
}

Просмотреть файл

@ -12,7 +12,7 @@ namespace NSubstitute.Routing
new ClearUnusedCallSpecHandler(state)
, new AddCallToQueryResultHandler(state.SubstitutionContext, state.CallSpecificationFactory)
, new ReturnConfiguredResultHandler(state.CallResults)
, new ReturnAutoValue(AutoValueBehaviour.UseValueForSubsequentCalls, state.AutoValueProviders, state.ConfigureCall)
, new ReturnAutoValue(AutoValueBehaviour.UseValueForSubsequentCalls, state.AutoValueProviders, state.AutoValuesCallResults, state.CallSpecificationFactory)
, ReturnDefaultForReturnTypeHandler()
});
}
@ -22,7 +22,7 @@ namespace NSubstitute.Routing
new ClearLastCallRouterHandler(state.SubstitutionContext)
, new ClearUnusedCallSpecHandler(state)
, new CheckReceivedCallsHandler(state.ReceivedCalls, state.CallSpecificationFactory, new ReceivedCallsExceptionThrower(), matchArgs, requiredQuantity)
, new ReturnAutoValue(AutoValueBehaviour.ReturnAndForgetValue, state.AutoValueProviders, state.ConfigureCall)
, new ReturnAutoValue(AutoValueBehaviour.ReturnAndForgetValue, state.AutoValueProviders, state.AutoValuesCallResults, state.CallSpecificationFactory)
, ReturnDefaultForReturnTypeHandler()
});
}
@ -59,7 +59,7 @@ namespace NSubstitute.Routing
new RecordCallSpecificationHandler(state.PendingSpecification, state.CallSpecificationFactory, state.CallActions)
, new PropertySetterHandler(new PropertyHelper(), state.ConfigureCall)
, new ReturnConfiguredResultHandler(state.CallResults)
, new ReturnAutoValue(AutoValueBehaviour.UseValueForSubsequentCalls, state.AutoValueProviders, state.ConfigureCall)
, new ReturnAutoValue(AutoValueBehaviour.UseValueForSubsequentCalls, state.AutoValueProviders, state.AutoValuesCallResults, state.CallSpecificationFactory)
, new ReturnFromAndConfigureDynamicCall(state.ConfigureCall)
, ReturnDefaultForReturnTypeHandler()
});
@ -75,7 +75,8 @@ namespace NSubstitute.Routing
, new ReturnConfiguredResultHandler(state.CallResults)
, new ReturnResultForTypeHandler(state.ResultsForType)
, new ReturnFromBaseIfRequired(state.SubstituteConfig, state.CallBaseExclusions)
, new ReturnAutoValue(AutoValueBehaviour.UseValueForSubsequentCalls, state.AutoValueProviders, state.ConfigureCall)
, new ReturnFromCustomHandlers(state.CustomHandlers)
, new ReturnAutoValue(AutoValueBehaviour.UseValueForSubsequentCalls, state.AutoValueProviders, state.AutoValuesCallResults, state.CallSpecificationFactory)
, new ReturnFromAndConfigureDynamicCall(state.ConfigureCall)
, ReturnDefaultForReturnTypeHandler()
});