Adding call base exclusions (When..DoNotCallBase)

This commit is contained in:
David Tchepak 2014-01-01 16:25:57 +11:00
Родитель d426c93754
Коммит 5e34e1b701
14 изменённых файлов: 114 добавлений и 10 удалений

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

@ -1,7 +1,5 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using NSubstitute.Acceptance.Specs.Infrastructure;
using NUnit.Framework;
namespace NSubstitute.Acceptance.Specs

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

@ -69,8 +69,9 @@ namespace NSubstitute.Acceptance.Specs
var wasCalled = false;
var testClass = Substitute.ForPartsOf<TestClass>();
testClass.When(x => x.VoidAbstractMethod())
.DoNotCallBase()
.Do(x => wasCalled = true);
testClass.When(x => x.VoidAbstractMethod())
.DoNotCallBase();
testClass.VoidAbstractMethod();
Assert.That(testClass.CalledTimes, Is.EqualTo(0));
Assert.That(wasCalled);

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

@ -0,0 +1,30 @@
using NSubstitute.Core;
using NSubstitute.Specs.Infrastructure;
using NUnit.Framework;
namespace NSubstitute.Specs
{
public class CallBaseExclusionsSpecs : ConcernFor<CallBaseExclusions>
{
public override CallBaseExclusions CreateSubjectUnderTest() { return new CallBaseExclusions(); }
[Test]
public void Exclude_call()
{
var call = mock<ICall>();
var spec = mock<ICallSpecification>();
spec.stub(x => x.IsSatisfiedBy(call)).Return(true);
sut.Exclude(spec);
Assert.That(sut.IsExcluded(call), Is.True);
}
[Test]
public void Non_excluded_call()
{
var call = mock<ICall>();
Assert.That(sut.IsExcluded(call), Is.False);
}
}
}

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

@ -90,6 +90,7 @@
<Compile Include="Arguments\NonParamsArgumentSpecificationFactorySpecs.cs" />
<Compile Include="Arguments\ParamsArgumentSpecificationFactorySpecs.cs" />
<Compile Include="CallActionsSpecs.cs" />
<Compile Include="CallBaseExclusionsSpecs.cs" />
<Compile Include="CallFactorySpecs.cs" />
<Compile Include="CallFormatterSpecs.cs" />
<Compile Include="CallInfoFactorySpecs.cs" />

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

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

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

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

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

@ -16,6 +16,7 @@ namespace NSubstitute.Core
IConfigureCall ConfigureCall { get; }
IEventHandlerRegistry EventHandlerRegistry { get; }
IAutoValueProvider[] AutoValueProviders { get; }
ICallBaseExclusions CallBaseExclusions { get; }
void ClearUnusedCallSpecs();
}
}

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

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

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

@ -30,10 +30,13 @@ namespace NSubstitute.Core
_call(_substitute);
}
public WhenCalled<T> DoNotCallBase()
/// <summary>
/// Do not call the base implementation on future calls. For us with partial substitutes.
/// </summary>
public void DoNotCallBase()
{
//TODO: stop this call from going through to base
return this;
_callRouter.SetRoute(x => _routeFactory.DoNotCallBase(x, _matchArgs));
_call(_substitute);
}
}
}

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

@ -115,6 +115,7 @@
<Compile Include="Core\Arguments\ParamsArgumentSpecificationFactory.cs" />
<Compile Include="Core\Arguments\SuppliedArgumentSpecifications.cs" />
<Compile Include="Core\Arguments\SuppliedArgumentSpecificationsFactory.cs" />
<Compile Include="Core\CallBaseExclusions.cs" />
<Compile Include="Core\CallFactory.cs" />
<Compile Include="Core\CallSpecAndTarget.cs" />
<Compile Include="Core\CallSpecificationFactoryFactoryYesThatsRight.cs" />
@ -124,6 +125,7 @@
<Compile Include="Core\Arguments\IArgumentEqualsSpecificationFactory.cs" />
<Compile Include="Core\Extensions.cs" />
<Compile Include="Core\GetCallSpec.cs" />
<Compile Include="Core\ICallBaseExclusions.cs" />
<Compile Include="Core\ICallRouterProvider.cs" />
<Compile Include="Core\IGetCallSpec.cs" />
<Compile Include="Core\Maybe.cs" />
@ -169,6 +171,7 @@
<Compile Include="Routing\Handlers\AddCallToQueryResultHandler.cs" />
<Compile Include="Routing\Handlers\ClearLastCallRouterHandler.cs" />
<Compile Include="Routing\Handlers\ClearUnusedCallSpecHandler.cs" />
<Compile Include="Routing\Handlers\DoNotCallBaseForCallHandler.cs" />
<Compile Include="Routing\Handlers\ReturnAutoValueForThisAndSubsequentCallsHandler.cs" />
<Compile Include="Routing\Handlers\RecordCallSpecificationHandler.cs" />
<Compile Include="Core\MatchArgs.cs" />

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

@ -0,0 +1,25 @@
using NSubstitute.Core;
namespace NSubstitute.Routing.Handlers
{
public class DoNotCallBaseForCallHandler :ICallHandler
{
private readonly ICallSpecificationFactory _callSpecificationFactory;
private readonly ICallBaseExclusions _exclusions;
private readonly MatchArgs _matchArgs;
public DoNotCallBaseForCallHandler(ICallSpecificationFactory callSpecificationFactory, ICallBaseExclusions exclusions, MatchArgs matchArgs)
{
_callSpecificationFactory = callSpecificationFactory;
_exclusions = exclusions;
_matchArgs = matchArgs;
}
public RouteAction Handle(ICall call)
{
var callSpec = _callSpecificationFactory.CreateFrom(call, _matchArgs);
_exclusions.Exclude(callSpec);
return RouteAction.Continue();
}
}
}

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

@ -5,15 +5,18 @@ namespace NSubstitute.Routing.Handlers
public class ReturnFromBaseIfRequired : ICallHandler
{
private readonly bool _required;
private readonly ICallBaseExclusions _callBaseExclusions;
public ReturnFromBaseIfRequired(bool required)
public ReturnFromBaseIfRequired(bool required, ICallBaseExclusions callBaseExclusions)
{
_required = required;
_callBaseExclusions = callBaseExclusions;
}
public RouteAction Handle(ICall call)
{
if (!_required) return RouteAction.Continue();
if (_callBaseExclusions.IsExcluded(call)) return RouteAction.Continue();
return call
.TryCallBase()

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

@ -8,6 +8,7 @@ namespace NSubstitute.Routing
IRoute CallQuery(ISubstituteState state);
IRoute CheckReceivedCalls(ISubstituteState state, MatchArgs matchArgs, Quantity requiredQuantity);
IRoute DoWhenCalled(ISubstituteState state, Action<CallInfo> doAction, MatchArgs matchArgs);
IRoute DoNotCallBase(ISubstituteState state, MatchArgs matchArgs);
IRoute RaiseEvent(ISubstituteState state, Func<ICall, object[]> getEventArguments);
IRoute RecordCallSpecification(ISubstituteState state);
IRoute RecordReplay(ISubstituteState state);

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

@ -34,6 +34,15 @@ namespace NSubstitute.Routing
, ReturnDefaultForReturnTypeHandler()
});
}
public IRoute DoNotCallBase(ISubstituteState state, MatchArgs matchArgs)
{
return new Route(new ICallHandler[] {
new ClearLastCallRouterHandler(state.SubstitutionContext)
, new ClearUnusedCallSpecHandler(state)
, new DoNotCallBaseForCallHandler(state.CallSpecificationFactory, state.CallBaseExclusions, matchArgs)
, ReturnDefaultForReturnTypeHandler()
});
}
public IRoute RaiseEvent(ISubstituteState state, Func<ICall, object[]> getEventArguments)
{
return new Route(new ICallHandler[] {
@ -62,7 +71,7 @@ namespace NSubstitute.Routing
, new PropertySetterHandler(new PropertyHelper(), state.ConfigureCall)
, new DoActionsCallHandler(state.CallActions)
, new ReturnConfiguredResultHandler(state.CallResults)
, new ReturnFromBaseIfRequired(state.CallBaseByDefault)
, new ReturnFromBaseIfRequired(state.CallBaseByDefault, state.CallBaseExclusions)
, new ReturnAutoValueForThisAndSubsequentCallsHandler(state.AutoValueProviders, state.ConfigureCall)
, ReturnDefaultForReturnTypeHandler()
});