Spiking configuring CallBase using returns

This commit is contained in:
David Tchepak 2013-07-21 22:08:30 +10:00
Родитель a30ca18ea1
Коммит b3ae935769
15 изменённых файлов: 72 добавлений и 90 удалений

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

@ -23,7 +23,7 @@ namespace NSubstitute.Specs
public override void Context()
{
_call = mock<ICall>();
_callInfo = new CallInfo(new Argument[0]);
_callInfo = new CallInfo(new Argument[0], null);
_callInfoFactory = mock<ICallInfoFactory>();
_callInfoFactory.stub(x => x.Create(_call)).Return(_callInfo);
}

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

@ -63,7 +63,7 @@ namespace NSubstitute.Specs
public override CallInfo CreateSubjectUnderTest()
{
return new CallInfo(_arguments);
return new CallInfo(_arguments, null);
}
}
@ -72,7 +72,7 @@ namespace NSubstitute.Specs
[Test]
public void Match_argument_by_declared_type_when_an_exact_match_is_found()
{
var sut = new CallInfo(new[] { CreateArg<object>("hello"), CreateArg("world") });
var sut = new CallInfo(new[] { CreateArg<object>("hello"), CreateArg("world") }, null);
Assert.That(sut.Arg<object>(), Is.EqualTo("hello"));
Assert.That(sut.Arg<string>(), Is.EqualTo("world"));
@ -81,7 +81,7 @@ namespace NSubstitute.Specs
[Test]
public void Match_argument_by_actual_type_when_no_declared_type_match_is_found()
{
var sut = new CallInfo(new[] { CreateArg<object>(123), CreateArg<object>("hello") });
var sut = new CallInfo(new[] { CreateArg<object>(123), CreateArg<object>("hello") }, null);
Assert.That(sut.Arg<string>(), Is.EqualTo("hello"));
Assert.That(sut.Arg<int>(), Is.EqualTo(123));
@ -91,7 +91,7 @@ namespace NSubstitute.Specs
public void Match_argument_by_actual_type_when_no_declared_type_match_is_found_and_when_a_compatible_argument_is_provided()
{
var list = new List<int>();
var sut = new CallInfo(new[] { CreateArg<object>("asdf"), CreateArg<object>(list) });
var sut = new CallInfo(new[] { CreateArg<object>("asdf"), CreateArg<object>(list) }, null);
Assert.That(sut.Arg<IEnumerable<int>>(), Is.SameAs(list));
}
@ -99,7 +99,7 @@ namespace NSubstitute.Specs
public void Match_by_ref_type_arguments_when_argument_that_is_the_non_by_ref_type_is_provided()
{
const int expectedResult = 5;
var sut = new CallInfo(new[] { CreateArg<object>("aasdf"), new ByRefArgument<int>(expectedResult) });
var sut = new CallInfo(new[] { CreateArg<object>("aasdf"), new ByRefArgument<int>(expectedResult) }, null);
Assert.That(sut.Arg<int>(), Is.EqualTo(expectedResult));
}
@ -107,14 +107,14 @@ namespace NSubstitute.Specs
public void Match_by_ref_type_arguments_when_argument_compatbile_non_by_ref_type_is_provided()
{
var list = new List<int>();
var sut = new CallInfo(new[] { CreateArg<object>("aasdf"), new ByRefArgument<List<int>>(list) });
var sut = new CallInfo(new[] { CreateArg<object>("aasdf"), new ByRefArgument<List<int>>(list) }, null);
Assert.That(sut.Arg<IEnumerable<int>>(), Is.EqualTo(list));
}
[Test]
public void Throw_when_there_is_no_declared_type_match_but_multiple_compatible_arguments()
{
var sut = new CallInfo(new[] { CreateArg<object>("a"), CreateArg<object>("b") });
var sut = new CallInfo(new[] { CreateArg<object>("a"), CreateArg<object>("b") }, null);
Assert.Throws<AmbiguousArgumentsException>(() => sut.Arg<string>());
}
}
@ -124,7 +124,7 @@ namespace NSubstitute.Specs
[Test]
public void Throw_when_setting_argument_that_is_not_passed_by_ref()
{
var sut = new CallInfo(new[] { CreateArg(1) });
var sut = new CallInfo(new[] { CreateArg(1) }, null);
Assert.Throws<ArgumentIsNotOutOrRefException>(() => sut[0] = 123);
}
@ -132,7 +132,7 @@ namespace NSubstitute.Specs
[Test]
public void Throw_when_setting_by_ref_argument_with_an_incompatible_value()
{
var sut = new CallInfo(new[] { new ByRefArgument<object>("needs a string") });
var sut = new CallInfo(new[] { new ByRefArgument<object>("needs a string") }, null);
Assert.Throws<ArgumentSetWithIncompatibleValueException>(() => sut[0] = new object());
}

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

@ -23,7 +23,7 @@ namespace NSubstitute.Specs
protected CallInfo StubCallInfoForCall(ICall call)
{
var callInfo = new CallInfo(new Argument[0]);
var callInfo = new CallInfo(new Argument[0], null);
_callInfoFactory.stub(x => x.Create(call)).Return(callInfo);
return callInfo;
}

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

@ -17,7 +17,7 @@ namespace NSubstitute.Specs
public override void Context()
{
_callInfo = new CallInfo(new Argument[0]);
_callInfo = new CallInfo(new Argument[0], null);
_func = mock<Func<CallInfo, string>>();
_func.stub(x => x(_callInfo)).Return(ValueToReturn);
}
@ -44,7 +44,7 @@ namespace NSubstitute.Specs
[Test]
public void Should_return_null()
{
Assert.That(sut.ReturnFor(new CallInfo(new Argument[0])), Is.Null);
Assert.That(sut.ReturnFor(new CallInfo(new Argument[0], null)), Is.Null);
}
public override ReturnValueFromFunc<string> CreateSubjectUnderTest()

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

@ -1,20 +0,0 @@
using System.Collections.Generic;
using System.Linq;
namespace NSubstitute.Core
{
public class CallBaseSpecifications : ICallBaseSpecifications
{
readonly List<ICallSpecification> _callSpecifications = new List<ICallSpecification>();
public void Add(ICallSpecification callSpecification)
{
_callSpecifications.Add(callSpecification);
}
public bool DoesCallBase(ICall callInfo)
{
return _callSpecifications.Any(cs => cs.IsSatisfiedBy(callInfo));
}
}
}

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

@ -8,12 +8,19 @@ namespace NSubstitute.Core
public class CallInfo
{
private readonly Argument[] _callArguments;
private readonly Func<object> _callBase;
public CallInfo(Argument[] callArguments)
public CallInfo(Argument[] callArguments, Func<object> callBase)
{
_callArguments = callArguments;
_callBase = callBase;
}
/// <summary>
/// Gets the nth argument to this call.
/// </summary>
/// <param name="index">Index of argument</param>
/// <returns>The value of the argument at the given index</returns>
public object this[int index]
{
get { return _callArguments[index].Value; }
@ -38,16 +45,30 @@ namespace NSubstitute.Core
}
}
/// <summary>
/// Get the arguments passed to this call.
/// </summary>
/// <returns>Array of all arguments passed to this call</returns>
public object[] Args()
{
return _callArguments.Select(x => x.Value).ToArray();
}
/// <summary>
/// Gets the types of all the arguments passed to this call.
/// </summary>
/// <returns>Array of types of all arguments passed to this call</returns>
public Type[] ArgTypes()
{
return _callArguments.Select(x => x.DeclaredType).ToArray();
}
/// <summary>
/// Gets the argument of type `T` passed to this call. This will throw if there are no arguments
/// of this type, or if there is more than one matching argument.
/// </summary>
/// <typeparam name="T">The type of the argument to retrieve</typeparam>
/// <returns>The argument passed to the call, or throws if there is not exactly one argument of this type</returns>
public T Arg<T>()
{
T arg;
@ -56,6 +77,15 @@ namespace NSubstitute.Core
throw new ArgumentNotFoundException("Can not find an argument of type " + typeof(T).FullName + " to this call.");
}
/// <summary>
/// Call the underlying base implementation of this call, if this is for a virtual member.
/// </summary>
/// <returns></returns>
public object CallBase()
{
return _callBase();
}
private bool TryGetArg<T>(Func<Argument, bool> condition, out T value)
{
value = default(T);

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

@ -9,7 +9,7 @@ namespace NSubstitute.Core
public CallInfo Create(ICall call)
{
var arguments = GetArgumentsFromCall(call).ToArray();
return new CallInfo(arguments);
return new CallInfo(arguments, call.CallBase);
}
private static IEnumerable<Argument> GetArgumentsFromCall(ICall call)

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

@ -1,8 +0,0 @@
namespace NSubstitute.Core
{
public interface ICallBaseSpecifications
{
void Add(ICallSpecification callSpecification);
bool DoesCallBase(ICall callInfo);
}
}

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

@ -1,5 +1,4 @@
using System;
using NSubstitute.Routing.AutoValues;
using NSubstitute.Routing.AutoValues;
namespace NSubstitute.Core
{
@ -12,7 +11,6 @@ namespace NSubstitute.Core
ICallResults CallResults { get; }
ICallSpecificationFactory CallSpecificationFactory { get; }
ICallActions CallActions { get; }
ICallBaseSpecifications CallBaseSpecifications { get; }
bool CallBaseByDefault { get; set; }
SequenceNumberGenerator SequenceNumberGenerator { get; }
IConfigureCall ConfigureCall { get; }

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

@ -11,7 +11,6 @@ namespace NSubstitute.Core
public ICallResults CallResults { get; private set; }
public ICallSpecificationFactory CallSpecificationFactory { get; private set; }
public ICallActions CallActions { get; private set; }
public ICallBaseSpecifications CallBaseSpecifications { get; private set; }
public bool CallBaseByDefault { get; set; }
public SequenceNumberGenerator SequenceNumberGenerator { get; private set; }
public IConfigureCall ConfigureCall { get; private set; }
@ -31,7 +30,6 @@ namespace NSubstitute.Core
CallResults = new CallResults(callInfoFactory);
CallSpecificationFactory = CallSpecificationFactoryFactoryYesThatsRight.CreateCallSpecFactory();
CallActions = new CallActions(callInfoFactory);
CallBaseSpecifications = new CallBaseSpecifications();
var getCallSpec = new GetCallSpec(callStack, PendingSpecification, CallSpecificationFactory, CallActions);

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

@ -115,7 +115,6 @@
<Compile Include="Core\Arguments\ParamsArgumentSpecificationFactory.cs" />
<Compile Include="Core\Arguments\SuppliedArgumentSpecifications.cs" />
<Compile Include="Core\Arguments\SuppliedArgumentSpecificationsFactory.cs" />
<Compile Include="Core\CallBaseSpecifications.cs" />
<Compile Include="Core\CallFactory.cs" />
<Compile Include="Core\CallSpecAndTarget.cs" />
<Compile Include="Core\CallSpecificationFactoryFactoryYesThatsRight.cs" />
@ -125,7 +124,6 @@
<Compile Include="Core\Arguments\IArgumentEqualsSpecificationFactory.cs" />
<Compile Include="Core\Extensions.cs" />
<Compile Include="Core\GetCallSpec.cs" />
<Compile Include="Core\ICallBaseSpecifications.cs" />
<Compile Include="Core\ICallRouterProvider.cs" />
<Compile Include="Core\IGetCallSpec.cs" />
<Compile Include="Core\SequenceChecking\InstanceTracker.cs" />
@ -191,7 +189,6 @@
<Compile Include="Core\IReturn.cs" />
<Compile Include="Core\PropertyCallFormatter.cs" />
<Compile Include="Core\ReflectionExtensions.cs" />
<Compile Include="Routing\Handlers\ReturnBaseResultCallHandler.cs" />
<Compile Include="Routing\Handlers\SetBaseForCallHandler.cs" />
<Compile Include="Routing\IRouteFactory.cs" />
<Compile Include="Routing\Route.cs" />

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

@ -10,17 +10,22 @@ namespace NSubstitute.Proxies.CastleDynamicProxy
public virtual ICall Map(IInvocation castleInvocation)
{
Func<object> baseMethod = null;
if (castleInvocation.InvocationTarget != null &&
castleInvocation.MethodInvocationTarget.IsAbstract != true)
{
baseMethod = () =>
{
//Func<object> baseMethod = null;
//if (castleInvocation.InvocationTarget != null &&
// castleInvocation.MethodInvocationTarget.IsAbstract != true)
//{
// baseMethod = () =>
// {
// castleInvocation.Proceed();
// return castleInvocation.ReturnValue;
// };
//}
Func<object> baseMethod = () =>
{
castleInvocation.Proceed();
return castleInvocation.ReturnValue;
};
}
return CallFactory.Create(castleInvocation.Method, castleInvocation.Arguments, castleInvocation.Proxy, baseMethod);
}

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

@ -1,26 +0,0 @@
using NSubstitute.Core;
namespace NSubstitute.Routing.Handlers
{
public class ReturnBaseResultCallHandler : ICallHandler
{
private readonly ISubstituteState _substituteState;
private readonly ICallBaseSpecifications _callBaseSpecifications;
public ReturnBaseResultCallHandler(ISubstituteState substituteState, ICallBaseSpecifications callBaseSpecifications)
{
_substituteState = substituteState;
_callBaseSpecifications = callBaseSpecifications;
}
public RouteAction Handle(ICall call)
{
if (_callBaseSpecifications.DoesCallBase(call) || _substituteState.CallBaseByDefault)
{
return RouteAction.Return(call.CallBase());
}
return RouteAction.Continue();
}
}
}

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

@ -8,13 +8,13 @@ namespace NSubstitute.Routing.Handlers
public class SetBaseForCallHandler : ICallHandler
{
private readonly ICallSpecificationFactory _callSpecificationFactory;
private readonly ICallBaseSpecifications _callBaseSpecifications;
private readonly ICallResults _callResults;
private readonly MatchArgs _matchArgs;
public SetBaseForCallHandler(ICallSpecificationFactory callSpecificationFactory, ICallBaseSpecifications callBaseSpecifications, MatchArgs matchArgs)
public SetBaseForCallHandler(ICallSpecificationFactory callSpecificationFactory, ICallResults callResults, MatchArgs matchArgs)
{
_callSpecificationFactory = callSpecificationFactory;
_callBaseSpecifications = callBaseSpecifications;
_callResults = callResults;
_matchArgs = matchArgs;
}
@ -26,7 +26,7 @@ namespace NSubstitute.Routing.Handlers
throw new CouldNotCallBaseException(method);
}
var callSpec = _callSpecificationFactory.CreateFrom(call, _matchArgs);
_callBaseSpecifications.Add(callSpec);
_callResults.SetResult(callSpec, new ReturnValueFromBase(method.ReturnType));
return RouteAction.Continue();
}
@ -34,5 +34,14 @@ namespace NSubstitute.Routing.Handlers
{
return methodInfo.IsVirtual && !methodInfo.IsFinal && !methodInfo.IsAbstract;
}
class ReturnValueFromBase : IReturn
{
private readonly Type _expectedType;
public ReturnValueFromBase(Type expectedType) { _expectedType = expectedType; }
public object ReturnFor(CallInfo info) { return info.CallBase(); }
public Type TypeOrNull() { return _expectedType; }
public bool CanBeAssignedTo(Type t) { return _expectedType.IsAssignableFrom(t); }
}
}
}

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

@ -11,7 +11,7 @@ namespace NSubstitute.Routing
return new Route(new ICallHandler[] {
new ClearLastCallRouterHandler(state.SubstitutionContext)
, new ClearUnusedCallSpecHandler(state)
, new SetBaseForCallHandler(state.CallSpecificationFactory, state.CallBaseSpecifications, matchArgs)
, new SetBaseForCallHandler(state.CallSpecificationFactory, state.CallResults, matchArgs)
, ReturnDefaultForReturnTypeHandler()
});
}
@ -71,7 +71,6 @@ namespace NSubstitute.Routing
, new PropertySetterHandler(new PropertyHelper(), state.ConfigureCall)
, new DoActionsCallHandler(state.CallActions)
, new ReturnConfiguredResultHandler(state.CallResults)
, new ReturnBaseResultCallHandler(state, state.CallBaseSpecifications)
, new ReturnAutoValueForThisAndSubsequentCallsHandler(state.AutoValueProviders, state.ConfigureCall)
, ReturnDefaultForReturnTypeHandler()
});