Skip to content

Commit 9638d0d

Browse files
committed
Merge pull request #68 from MatKubicki/master
Fixing #62 - Multithreaded test not working
2 parents 69bf046 + 85bc6c6 commit 9638d0d

File tree

6 files changed

+164
-164
lines changed

6 files changed

+164
-164
lines changed

Source/IInterceptStrategy.cs

+102-14
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Linq;
44
using System.Text;
55
using Moq.Proxy;
6+
using System.Reflection;
67

78
namespace Moq
89
{
@@ -26,28 +27,115 @@ internal interface IInterceptStrategy
2627

2728
internal class InterceptStrategyContext
2829
{
29-
public InterceptStrategyContext(Mock Mock
30-
, Type targetType
31-
, Dictionary<string, List<Delegate>> invocationLists
32-
, List<ICallContext> actualInvocations
33-
, MockBehavior behavior
34-
, List<IProxyCall> orderedCalls
35-
)
30+
private Dictionary<string, List<Delegate>> invocationLists = new Dictionary<string, List<Delegate>>();
31+
private List<ICallContext> actualInvocations = new List<ICallContext>();
32+
private List<IProxyCall> orderedCalls = new List<IProxyCall>();
33+
34+
public InterceptStrategyContext(Mock Mock, Type targetType, MockBehavior behavior)
3635
{
3736
this.Behavior = behavior;
3837
this.Mock = Mock;
39-
this.InvocationLists = invocationLists;
40-
this.ActualInvocations = actualInvocations;
4138
this.TargetType = targetType;
42-
this.OrderedCalls = orderedCalls;
4339
}
44-
public Mock Mock {get;private set;}
40+
public Mock Mock { get; private set; }
4541
public Type TargetType { get; private set; }
46-
public Dictionary<string, List<Delegate>> InvocationLists { get; private set; }
47-
public List<ICallContext> ActualInvocations { get; private set; }
4842
public MockBehavior Behavior { get; private set; }
49-
public List<IProxyCall> OrderedCalls { get; private set; }
5043
public IProxyCall CurrentCall { get; set; }
44+
45+
#region InvocationLists
46+
internal IEnumerable<Delegate> GetInvocationList(EventInfo ev)
47+
{
48+
lock (invocationLists)
49+
{
50+
List<Delegate> handlers;
51+
if (!invocationLists.TryGetValue(ev.Name, out handlers))
52+
{
53+
return new Delegate[0];
54+
}
55+
56+
return handlers.ToList();
57+
}
58+
}
59+
60+
internal void AddEventHandler(EventInfo ev, Delegate handler)
61+
{
62+
lock (invocationLists)
63+
{
64+
List<Delegate> handlers;
65+
if (!invocationLists.TryGetValue(ev.Name, out handlers))
66+
{
67+
handlers = new List<Delegate>();
68+
invocationLists.Add(ev.Name, handlers);
69+
}
70+
71+
handlers.Add(handler);
72+
}
73+
}
74+
internal void RemoveEventHandler(EventInfo ev, Delegate handler)
75+
{
76+
lock (invocationLists)
77+
{
78+
List<Delegate> handlers;
79+
if (invocationLists.TryGetValue(ev.Name, out handlers))
80+
{
81+
handlers.Remove(handler);
82+
}
83+
}
84+
}
85+
#endregion
86+
#region ActualInvocations
87+
internal void AddInvocation(ICallContext invocation)
88+
{
89+
lock (actualInvocations)
90+
{
91+
actualInvocations.Add(invocation);
92+
}
93+
}
94+
internal IEnumerable<ICallContext> ActualInvocations
95+
{
96+
get
97+
{
98+
lock (actualInvocations)
99+
{
100+
return actualInvocations.ToList();
101+
}
102+
}
103+
}
104+
internal void ClearInvocations()
105+
{
106+
lock (actualInvocations)
107+
{
108+
actualInvocations.Clear();
109+
}
110+
}
111+
#endregion
112+
#region OrderedCalls
113+
internal void AddOrderedCall(IProxyCall call)
114+
{
115+
lock (orderedCalls)
116+
{
117+
orderedCalls.Add(call);
118+
}
119+
}
120+
internal void RemoveOrderedCall(IProxyCall call)
121+
{
122+
lock (orderedCalls)
123+
{
124+
orderedCalls.Remove(call);
125+
}
126+
}
127+
internal IEnumerable<IProxyCall> OrderedCalls
128+
{
129+
get
130+
{
131+
lock (orderedCalls)
132+
{
133+
return orderedCalls.ToList();
134+
}
135+
}
136+
}
137+
#endregion
138+
51139
}
52140

53141
}

Source/Interceptor.cs

+10-56
Original file line numberDiff line numberDiff line change
@@ -54,37 +54,14 @@ namespace Moq
5454
/// </summary>
5555
internal class Interceptor : ICallInterceptor
5656
{
57-
private MockBehavior behavior;
58-
private Type targetType;
5957
private Dictionary<ExpressionKey, IProxyCall> calls = new Dictionary<ExpressionKey, IProxyCall>();
60-
private Dictionary<string, List<Delegate>> invocationLists = new Dictionary<string, List<Delegate>>();
61-
private List<IProxyCall> orderedCalls = new List<IProxyCall>();
62-
private List<ICallContext> actualInvocations = new List<ICallContext>();
6358

6459
public Interceptor(MockBehavior behavior, Type targetType, Mock mock)
6560
{
66-
this.behavior = behavior;
67-
this.targetType = targetType;
68-
this.Mock = mock;
61+
InterceptionContext = new InterceptStrategyContext(mock, targetType, behavior);
6962
}
7063

71-
internal IEnumerable<ICallContext> ActualCalls
72-
{
73-
get
74-
{
75-
lock (actualInvocations)
76-
{
77-
return this.actualInvocations;
78-
}
79-
}
80-
}
81-
82-
internal Mock Mock { get; private set; }
83-
84-
internal IEnumerable<IProxyCall> OrderedCalls
85-
{
86-
get { return this.orderedCalls; }
87-
}
64+
internal InterceptStrategyContext InterceptionContext { get; private set; }
8865

8966
internal void Verify()
9067
{
@@ -127,13 +104,13 @@ public void AddCall(IProxyCall call, SetupKind kind)
127104
if (calls.ContainsKey(key))
128105
{
129106
// Remove previous from ordered calls
130-
orderedCalls.Remove(calls[key]);
107+
InterceptionContext.RemoveOrderedCall(calls[key]);
131108
}
132109

133110
calls[key] = call;
134111
}
135112

136-
orderedCalls.Add(call);
113+
InterceptionContext.AddOrderedCall(call);
137114
}
138115

139116
private IEnumerable<IInterceptStrategy> InterceptionStrategies()
@@ -151,38 +128,15 @@ private IEnumerable<IInterceptStrategy> InterceptionStrategies()
151128
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
152129
public void Intercept(ICallContext invocation)
153130
{
154-
155-
lock (Mock) // this solves issue #249
156-
{
157-
var interceptionContext = new InterceptStrategyContext(Mock
158-
, targetType
159-
, invocationLists
160-
, actualInvocations
161-
, behavior
162-
, orderedCalls
163-
);
164-
foreach (var strategy in InterceptionStrategies())
165-
{
166-
if (InterceptionAction.Stop == strategy.HandleIntercept(invocation, interceptionContext))
167-
{
168-
break;
169-
}
170-
}
171-
}
172-
}
173-
174-
175-
internal IEnumerable<Delegate> GetInvocationList(EventInfo ev)
176-
{
177-
List<Delegate> handlers;
178-
if (!this.invocationLists.TryGetValue(ev.Name, out handlers))
131+
foreach (var strategy in InterceptionStrategies())
179132
{
180-
return new Delegate[0];
133+
if (InterceptionAction.Stop == strategy.HandleIntercept(invocation, InterceptionContext))
134+
{
135+
break;
136+
}
181137
}
182-
183-
return handlers;
184138
}
185-
139+
186140
private class ExpressionKey
187141
{
188142
private string fixedString;

Source/InterceptorStrategies.cs

+4-23
Original file line numberDiff line numberDiff line change
@@ -233,26 +233,7 @@ private static IEnumerable<Type> GetAncestorTypes(Type initialType)
233233
}
234234

235235
return initialType.GetInterfaces();
236-
}
237-
internal void AddEventHandler(EventInfo ev, Delegate handler)
238-
{
239-
List<Delegate> handlers;
240-
if (!ctx.InvocationLists.TryGetValue(ev.Name, out handlers))
241-
{
242-
handlers = new List<Delegate>();
243-
ctx.InvocationLists.Add(ev.Name, handlers);
244-
}
245-
246-
handlers.Add(handler);
247-
}
248-
internal void RemoveEventHandler(EventInfo ev, Delegate handler)
249-
{
250-
List<Delegate> handlers;
251-
if (ctx.InvocationLists.TryGetValue(ev.Name, out handlers))
252-
{
253-
handlers.Remove(handler);
254-
}
255-
}
236+
}
256237
InterceptStrategyContext ctx;
257238
public InterceptionAction HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx)
258239
{
@@ -272,7 +253,7 @@ public InterceptionAction HandleIntercept(ICallContext invocation, InterceptStra
272253
}
273254
else if (delegateInstance != null)
274255
{
275-
this.AddEventHandler(eventInfo, (Delegate)invocation.Arguments[0]);
256+
ctx.AddEventHandler(eventInfo, (Delegate)invocation.Arguments[0]);
276257
}
277258

278259
return InterceptionAction.Stop;
@@ -289,7 +270,7 @@ public InterceptionAction HandleIntercept(ICallContext invocation, InterceptStra
289270
}
290271
else if (delegateInstance != null)
291272
{
292-
this.RemoveEventHandler(eventInfo, (Delegate)invocation.Arguments[0]);
273+
ctx.RemoveEventHandler(eventInfo, (Delegate)invocation.Arguments[0]);
293274
}
294275

295276
return InterceptionAction.Stop;
@@ -300,7 +281,7 @@ public InterceptionAction HandleIntercept(ICallContext invocation, InterceptStra
300281
// mode we use to evaluate delegates by actually running them,
301282
// we don't want to count the invocation, or actually run
302283
// previous setups.
303-
ctx.ActualInvocations.Add(invocation);
284+
ctx.AddInvocation(invocation);
304285
}
305286
return InterceptionAction.Continue;
306287
}

Source/Mock.cs

+4-5
Original file line numberDiff line numberDiff line change
@@ -353,13 +353,12 @@ private static void VerifyCalls(
353353
Expression expression,
354354
Times times)
355355
{
356-
// .Where does an enumeration, and calls to a mocked method concurrent to VerifyCalls might change the content of ActualCalls. therefore, it is necessary to take a snapshot, using ToList(), so that concurrent calls will not impact the ongoing verification.
357-
var actualCalls = targetInterceptor.ActualCalls.ToList();
356+
IEnumerable<ICallContext> actualCalls = targetInterceptor.InterceptionContext.ActualInvocations;
358357

359358
var callCount = actualCalls.Where(ac => expected.Matches(ac)).Count();
360359
if (!times.Verify(callCount))
361360
{
362-
var setups = targetInterceptor.OrderedCalls.Where(oc => AreSameMethod(oc.SetupExpression, expression));
361+
var setups = targetInterceptor.InterceptionContext.OrderedCalls.Where(oc => AreSameMethod(oc.SetupExpression, expression));
363362
ThrowVerifyException(expected, setups, actualCalls, expression, times, callCount);
364363
}
365364
}
@@ -913,7 +912,7 @@ internal void DoRaise(EventInfo ev, EventArgs args)
913912
throw new InvalidOperationException(Resources.RaisedUnassociatedEvent);
914913
}
915914

916-
foreach (var del in this.Interceptor.GetInvocationList(ev).ToArray())
915+
foreach (var del in this.Interceptor.InterceptionContext.GetInvocationList(ev).ToArray())
917916
{
918917
del.InvokePreserveStack(this.Object, args);
919918
}
@@ -930,7 +929,7 @@ internal void DoRaise(EventInfo ev, params object[] args)
930929
throw new InvalidOperationException(Resources.RaisedUnassociatedEvent);
931930
}
932931

933-
foreach (var del in this.Interceptor.GetInvocationList(ev).ToArray())
932+
foreach (var del in this.Interceptor.InterceptionContext.GetInvocationList(ev).ToArray())
934933
{
935934
// Non EventHandler-compatible delegates get the straight
936935
// arguments, not the typical "sender, args" arguments.

Source/MockExtensions.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ public static class MockExtensions
2424
/// <param name="mock">The mock whose calls need to be reset.</param>
2525
public static void ResetCalls(this Mock mock)
2626
{
27-
var calls = (IList<ICallContext>)mock.Interceptor.ActualCalls;
28-
calls.Clear();
27+
mock.Interceptor.InterceptionContext.ClearInvocations();
2928
}
3029
}
3130
}

0 commit comments

Comments
 (0)