Skip to content

Commit

Permalink
Adding basic support for calling subs from multiple threads
Browse files Browse the repository at this point in the history
Adding acceptance test for calling from multiple threads.
Updated SubstituteContext to use ThreadLocal<T> from Rx.
Added reference to System.Threading distributed with Microsoft's Reacive Extensions (Rx) framework for .NET 3.5.
Adding Rx to acknowledgements.
  • Loading branch information
dtchepak committed Feb 5, 2011
1 parent 074a291 commit a69fd03
Show file tree
Hide file tree
Showing 9 changed files with 19,970 additions and 16 deletions.
46 changes: 46 additions & 0 deletions Source/NSubstitute.Acceptance.Specs/MultipleThreads.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Threading;
using NUnit.Framework;

namespace NSubstitute.Acceptance.Specs
{
public class MultipleThreads
{
[Test]
public void CallFromMultipleThreads()
{
var firstSub = Substitute.For<IFoo>();
var secondSub = Substitute.For<IFoo>();

using (var interrupted = new AutoResetEvent(false))
{

var initialThread = new Thread(() =>
{
firstSub.Number();
if (!interrupted.WaitOne(TimeSpan.FromSeconds(1))) Assert.Fail("Timed out waiting for interrupt");
1.Returns(1);
});
var interruptingThread = new Thread(() =>
{
secondSub.Number().Returns(2);
interrupted.Set();
});

initialThread.Start();
interruptingThread.Start();

initialThread.Join();
interruptingThread.Join();
}

Assert.That(firstSub.Number(), Is.EqualTo(1));
Assert.That(secondSub.Number(), Is.EqualTo(2));
}

public interface IFoo
{
int Number();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
<Compile Include="FieldReports\Issue33_RaisingINotifyPropertyChangedEvents.cs" />
<Compile Include="FieldReports\SubbingSynchronizationContext.cs" />
<Compile Include="Infrastructure\ICalculator.cs" />
<Compile Include="MultipleThreads.cs" />
<Compile Include="NotASubstituteExceptions.cs" />
<Compile Include="RecursiveSubs.cs" />
<Compile Include="SubbingForEventHandler.cs" />
Expand Down
33 changes: 17 additions & 16 deletions Source/NSubstitute/Core/SubstitutionContext.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading;
using NSubstitute.Core.Arguments;
using NSubstitute.Exceptions;
using NSubstitute.Proxies;
Expand All @@ -11,12 +12,13 @@ namespace NSubstitute.Core
{
public class SubstitutionContext : ISubstitutionContext
{

public static ISubstitutionContext Current { get; set; }

readonly ISubstituteFactory _substituteFactory;
ICallRouter _lastCallRouter;
IList<IArgumentSpecification> _argumentSpecifications;
Func<ICall, object[]> _getArgumentsForRaisingEvent;
readonly ThreadLocal<ICallRouter> _lastCallRouter = new ThreadLocal<ICallRouter>();
readonly ThreadLocal<IList<IArgumentSpecification>> _argumentSpecifications = new ThreadLocal<IList<IArgumentSpecification>>(() => new List<IArgumentSpecification>());
readonly ThreadLocal<Func<ICall, object[]>> _getArgumentsForRaisingEvent = new ThreadLocal<Func<ICall, object[]>>();

static SubstitutionContext()
{
Expand All @@ -32,7 +34,6 @@ static SubstitutionContext()
var proxyFactory = new ProxyFactory(delegateFactory, dynamicProxyFactory);
var callRouteResolver = new CallRouterResolver();
_substituteFactory = new SubstituteFactory(this, callRouterFactory, proxyFactory, callRouteResolver);
_argumentSpecifications = new List<IArgumentSpecification>();
}

public SubstitutionContext(ISubstituteFactory substituteFactory)
Expand All @@ -43,24 +44,24 @@ public SubstitutionContext(ISubstituteFactory substituteFactory)
public ISubstituteFactory SubstituteFactory { get { return _substituteFactory; } }

public void LastCallShouldReturn(IReturn value, MatchArgs matchArgs)
{
if (_lastCallRouter == null) throw new CouldNotSetReturnException();
_lastCallRouter.LastCallShouldReturn(value, matchArgs);
_lastCallRouter = null;
{
if (_lastCallRouter.Value == null) throw new CouldNotSetReturnException();
_lastCallRouter.Value.LastCallShouldReturn(value, matchArgs);
_lastCallRouter.Value = null;
}

public void LastCallRouter(ICallRouter callRouter)
{
_lastCallRouter = callRouter;
_lastCallRouter.Value = callRouter;
RaiseEventIfSet(callRouter);
}

void RaiseEventIfSet(ICallRouter callRouter)
{
if (_getArgumentsForRaisingEvent != null)
if (_getArgumentsForRaisingEvent.Value != null)
{
callRouter.SetRoute<RaiseEventRoute>(_getArgumentsForRaisingEvent);
_getArgumentsForRaisingEvent = null;
callRouter.SetRoute<RaiseEventRoute>(_getArgumentsForRaisingEvent.Value);
_getArgumentsForRaisingEvent.Value = null;
}
}

Expand All @@ -76,19 +77,19 @@ public ICallRouter GetCallRouterFor(object substitute)

public void EnqueueArgumentSpecification(IArgumentSpecification spec)
{
_argumentSpecifications.Add(spec);
_argumentSpecifications.Value.Add(spec);
}

public IList<IArgumentSpecification> DequeueAllArgumentSpecifications()
{
var result = _argumentSpecifications;
_argumentSpecifications = new List<IArgumentSpecification>();
var result = _argumentSpecifications.Value;
_argumentSpecifications.Value = new List<IArgumentSpecification>();
return result;
}

public void RaiseEventForNextCall(Func<ICall, object[]> getArguments)
{
_getArgumentsForRaisingEvent = getArguments;
_getArgumentsForRaisingEvent.Value = getArguments;
}
}
}
5 changes: 5 additions & 0 deletions Source/NSubstitute/NSubstitute.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Threading, Version=1.0.2838.102, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\ThirdParty\Rx\System.Threading.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
Expand Down
Binary file added ThirdParty/Rx/System.Threading.dll
Binary file not shown.

0 comments on commit a69fd03

Please sign in to comment.