Skip to content

Commit

Permalink
Create IAutoValueProvider factory with all supported providers
Browse files Browse the repository at this point in the history
Now it's possible to customize list of the auto-value providers
by injecting a customized dependency to the SubstituteFactory.
  • Loading branch information
zvirja authored and dtchepak committed Mar 30, 2018
1 parent e3b4bca commit 6087233
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 48 deletions.
26 changes: 7 additions & 19 deletions src/NSubstitute/Core/CallRouterFactory.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,22 @@
using System;
using NSubstitute.Routing;

namespace NSubstitute.Core
{
public class CallRouterFactory : ICallRouterFactory
{
private readonly SequenceNumberGenerator _sequenceNumberGenerator;
private readonly IThreadLocalContext _threadLocalContext;
private readonly IRouteFactory _routeFactory;
private readonly ICallSpecificationFactory _callSpecificationFactory;
private readonly ICallInfoFactory _callInfoFactory;

public CallRouterFactory(SequenceNumberGenerator sequenceNumberGenerator,
IRouteFactory routeFactory,
ICallSpecificationFactory callSpecificationFactory,
ICallInfoFactory callInfoFactory)
public CallRouterFactory(IThreadLocalContext threadLocalContext, IRouteFactory routeFactory)
{
_sequenceNumberGenerator = sequenceNumberGenerator;
_routeFactory = routeFactory;
_callSpecificationFactory = callSpecificationFactory;
_callInfoFactory = callInfoFactory;
_threadLocalContext = threadLocalContext ?? throw new ArgumentNullException(nameof(threadLocalContext));
_routeFactory = routeFactory ?? throw new ArgumentNullException(nameof(routeFactory));
}

public ICallRouter Create(SubstituteConfig config, IThreadLocalContext threadContext, ISubstituteFactory substituteFactory)
public ICallRouter Create(ISubstituteState substituteState)
{
var substituteState = new SubstituteState(config,
_sequenceNumberGenerator,
substituteFactory,
_callSpecificationFactory,
_callInfoFactory);

return new CallRouter(substituteState, threadContext, _routeFactory);
return new CallRouter(substituteState, _threadLocalContext, _routeFactory);
}
}
}
2 changes: 1 addition & 1 deletion src/NSubstitute/Core/ICallRouterFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ namespace NSubstitute.Core
{
public interface ICallRouterFactory
{
ICallRouter Create(SubstituteConfig config, IThreadLocalContext threadContext, ISubstituteFactory substituteFactory);
ICallRouter Create(ISubstituteState substituteState);
}
}
5 changes: 3 additions & 2 deletions src/NSubstitute/Core/ISubstituteState.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using NSubstitute.Routing.AutoValues;
using System.Collections.Generic;
using NSubstitute.Routing.AutoValues;

namespace NSubstitute.Core
{
Expand All @@ -11,7 +12,7 @@ public interface ISubstituteState
SequenceNumberGenerator SequenceNumberGenerator { get; }
IConfigureCall ConfigureCall { get; }
IEventHandlerRegistry EventHandlerRegistry { get; }
IAutoValueProvider[] AutoValueProviders { get; }
IReadOnlyCollection<IAutoValueProvider> AutoValueProviders { get; }
ICallResults AutoValuesCallResults { get; }
ICallBaseExclusions CallBaseExclusions { get; }
IResultsForType ResultsForType { get; }
Expand Down
7 changes: 7 additions & 0 deletions src/NSubstitute/Core/ISubstituteStateFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace NSubstitute.Core
{
public interface ISubstituteStateFactory
{
ISubstituteState Create(SubstituteConfig config, ISubstituteFactory substituteFactory);
}
}
12 changes: 6 additions & 6 deletions src/NSubstitute/Core/SubstituteFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,17 @@ namespace NSubstitute.Core
{
public class SubstituteFactory : ISubstituteFactory
{
private readonly IThreadLocalContext _threadContext;
private readonly ISubstituteStateFactory _substituteStateFactory;
private readonly ICallRouterFactory _callRouterFactory;
private readonly IProxyFactory _proxyFactory;

public SubstituteFactory(IThreadLocalContext threadContext, ICallRouterFactory callRouterFactory, IProxyFactory proxyFactory)
public SubstituteFactory(ISubstituteStateFactory substituteStateFactory, ICallRouterFactory callRouterFactory, IProxyFactory proxyFactory)
{
_threadContext = threadContext ?? throw new ArgumentNullException(nameof(threadContext));
_substituteStateFactory = substituteStateFactory ?? throw new ArgumentNullException(nameof(substituteStateFactory));
_callRouterFactory = callRouterFactory ?? throw new ArgumentNullException(nameof(callRouterFactory));
_proxyFactory = proxyFactory ?? throw new ArgumentNullException(nameof(proxyFactory));
}


/// <summary>
/// Create a substitute for the given types.
/// </summary>
Expand Down Expand Up @@ -48,9 +47,10 @@ public object CreatePartial(Type[] typesToProxy, object[] constructorArguments)
return Create(typesToProxy, constructorArguments, SubstituteConfig.CallBaseByDefault);
}

private object Create(Type[] typesToProxy, object[] constructorArguments, SubstituteConfig config)
private object Create(Type[] typesToProxy, object[] constructorArguments, SubstituteConfig config)
{
var callRouter = _callRouterFactory.Create(config, _threadContext, this);
var substituteState = _substituteStateFactory.Create(config, this);
var callRouter = _callRouterFactory.Create(substituteState);
var primaryProxyType = GetPrimaryProxyType(typesToProxy);
var additionalTypes = typesToProxy.Where(x => x != primaryProxyType).ToArray();
var proxy = _proxyFactory.GenerateProxy(callRouter, primaryProxyType, additionalTypes, constructorArguments);
Expand Down
18 changes: 6 additions & 12 deletions src/NSubstitute/Core/SubstituteState.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using NSubstitute.Routing.AutoValues;
using System.Collections.Generic;
using NSubstitute.Routing.AutoValues;

namespace NSubstitute.Core
{
Expand All @@ -12,20 +13,21 @@ public class SubstituteState : ISubstituteState
public SequenceNumberGenerator SequenceNumberGenerator { get; }
public IConfigureCall ConfigureCall { get; }
public IEventHandlerRegistry EventHandlerRegistry { get; }
public IAutoValueProvider[] AutoValueProviders { get; }
public IReadOnlyCollection<IAutoValueProvider> AutoValueProviders { get; }
public ICallResults AutoValuesCallResults { get; }
public IResultsForType ResultsForType { get; }
public ICustomHandlers CustomHandlers { get; }

public SubstituteState(
SubstituteConfig option,
SequenceNumberGenerator sequenceNumberGenerator,
ISubstituteFactory substituteFactory,
ICallSpecificationFactory callSpecificationFactory,
ICallInfoFactory callInfoFactory)
ICallInfoFactory callInfoFactory,
IReadOnlyCollection<IAutoValueProvider> autoValueProviders)
{
SubstituteConfig = option;
SequenceNumberGenerator = sequenceNumberGenerator;
AutoValueProviders = autoValueProviders;

var callCollection = new CallCollection();
ReceivedCalls = callCollection;
Expand All @@ -40,14 +42,6 @@ public SubstituteState(
ConfigureCall = new ConfigureCall(CallResults, CallActions, getCallSpec);
EventHandlerRegistry = new EventHandlerRegistry();

AutoValueProviders = new IAutoValueProvider[] {
new AutoObservableProvider(() => AutoValueProviders),
new AutoQueryableProvider(),
new AutoSubstituteProvider(substituteFactory),
new AutoStringProvider(),
new AutoArrayProvider(),
new AutoTaskProvider(() => AutoValueProviders),
};
}
}
}
34 changes: 34 additions & 0 deletions src/NSubstitute/Core/SubstituteStateFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using NSubstitute.Routing.AutoValues;

namespace NSubstitute.Core
{
public class SubstituteStateFactory : ISubstituteStateFactory
{
private readonly SequenceNumberGenerator _sequenceNumberGenerator;
private readonly ICallSpecificationFactory _callSpecificationFactory;
private readonly ICallInfoFactory _callInfoFactory;
private readonly IAutoValueProvidersFactory _autoValueProvidersFactory;

public SubstituteStateFactory(SequenceNumberGenerator sequenceNumberGenerator,
ICallSpecificationFactory callSpecificationFactory,
ICallInfoFactory callInfoFactory,
IAutoValueProvidersFactory autoValueProvidersFactory)
{
_sequenceNumberGenerator = sequenceNumberGenerator;
_callSpecificationFactory = callSpecificationFactory;
_callInfoFactory = callInfoFactory;
_autoValueProvidersFactory = autoValueProvidersFactory;
}

public ISubstituteState Create(SubstituteConfig config, ISubstituteFactory substituteFactory)
{
var autoValueProviders = _autoValueProvidersFactory.CreateProviders(substituteFactory);

return new SubstituteState(config,
_sequenceNumberGenerator,
_callSpecificationFactory,
_callInfoFactory,
autoValueProviders);
}
}
}
7 changes: 5 additions & 2 deletions src/NSubstitute/Core/SubstitutionContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using NSubstitute.Proxies.CastleDynamicProxy;
using NSubstitute.Proxies.DelegateProxy;
using NSubstitute.Routing;
using NSubstitute.Routing.AutoValues;

namespace NSubstitute.Core
{
Expand Down Expand Up @@ -34,12 +35,14 @@ private SubstitutionContext()

var sequenceNumberGenerator = new SequenceNumberGenerator();
var callInfoFactory = new CallInfoFactory();
var callRouterFactory = new CallRouterFactory(sequenceNumberGenerator, RouteFactory, callSpecificationFactory, callInfoFactory);
var autoValueProvidersFactory = new AutoValueProvidersFactory();
var substituteStateFactory = new SubstituteStateFactory(sequenceNumberGenerator, callSpecificationFactory, callInfoFactory, autoValueProvidersFactory);
var callRouterFactory = new CallRouterFactory(ThreadContext, RouteFactory);
var argSpecificationQueue = new ArgumentSpecificationDequeue(ThreadContext.DequeueAllArgumentSpecifications);
var dynamicProxyFactory = new CastleDynamicProxyFactory(argSpecificationQueue);
var delegateFactory = new DelegateProxyFactory(dynamicProxyFactory);
var proxyFactory = new ProxyFactory(delegateFactory, dynamicProxyFactory);
SubstituteFactory = new SubstituteFactory(ThreadContext, callRouterFactory, proxyFactory);
SubstituteFactory = new SubstituteFactory(substituteStateFactory, callRouterFactory, proxyFactory);
#pragma warning disable 618 // Obsolete
SequenceNumberGenerator = sequenceNumberGenerator;
#pragma warning restore 618 // Obsolete
Expand Down
7 changes: 4 additions & 3 deletions src/NSubstitute/Routing/AutoValues/AutoObservableProvider.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NSubstitute.Core;
Expand All @@ -7,9 +8,9 @@ namespace NSubstitute.Routing.AutoValues
{
public class AutoObservableProvider : IAutoValueProvider
{
private readonly Func<IAutoValueProvider[]> _autoValueProviders;
private readonly Lazy<IReadOnlyCollection<IAutoValueProvider>> _autoValueProviders;

public AutoObservableProvider(Func<IAutoValueProvider[]> autoValueProviders)
public AutoObservableProvider(Lazy<IReadOnlyCollection<IAutoValueProvider>> autoValueProviders)
{
_autoValueProviders = autoValueProviders;
}
Expand All @@ -25,7 +26,7 @@ public object GetValue(Type type)
throw new InvalidOperationException();

Type innerType = type.GetGenericArguments()[0];
var valueProvider = _autoValueProviders().FirstOrDefault(vp => vp.CanProvideValueFor(innerType));
var valueProvider = _autoValueProviders.Value.FirstOrDefault(vp => vp.CanProvideValueFor(innerType));
var value = valueProvider == null ? GetDefault(type) : valueProvider.GetValue(innerType);
return Activator.CreateInstance(
typeof(ReturnObservable<>).MakeGenericType(innerType)
Expand Down
7 changes: 4 additions & 3 deletions src/NSubstitute/Routing/AutoValues/AutoTaskProvider.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
Expand All @@ -7,9 +8,9 @@ namespace NSubstitute.Routing.AutoValues
{
public class AutoTaskProvider : IAutoValueProvider
{
private readonly Func<IAutoValueProvider[]> _autoValueProviders;
private readonly Lazy<IReadOnlyCollection<IAutoValueProvider>> _autoValueProviders;

public AutoTaskProvider(Func<IAutoValueProvider[]> autoValueProviders)
public AutoTaskProvider(Lazy<IReadOnlyCollection<IAutoValueProvider>> autoValueProviders)
{
_autoValueProviders = autoValueProviders;
}
Expand All @@ -27,7 +28,7 @@ public object GetValue(Type type)
if (type.GetTypeInfo().IsGenericType)
{
var taskType = type.GetGenericArguments()[0];
var valueProvider = _autoValueProviders().FirstOrDefault(vp => vp.CanProvideValueFor(taskType));
var valueProvider = _autoValueProviders.Value.FirstOrDefault(vp => vp.CanProvideValueFor(taskType));

var value = valueProvider == null ? GetDefault(type) : valueProvider.GetValue(taskType);
var taskCompletionSourceType = typeof(TaskCompletionSource<>).MakeGenericType(taskType);
Expand Down
30 changes: 30 additions & 0 deletions src/NSubstitute/Routing/AutoValues/AutoValueProvidersFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Threading;
using NSubstitute.Core;

namespace NSubstitute.Routing.AutoValues
{
public class AutoValueProvidersFactory : IAutoValueProvidersFactory
{
public IReadOnlyCollection<IAutoValueProvider> CreateProviders(ISubstituteFactory substituteFactory)
{
IAutoValueProvider[] result = null;
var lazyResult = new Lazy<IReadOnlyCollection<IAutoValueProvider>>(
() => result ?? throw new InvalidOperationException("Value was not constructed yet."),
LazyThreadSafetyMode.None);

result = new IAutoValueProvider[]
{
new AutoObservableProvider(lazyResult),
new AutoQueryableProvider(),
new AutoSubstituteProvider(substituteFactory),
new AutoStringProvider(),
new AutoArrayProvider(),
new AutoTaskProvider(lazyResult)
};

return result;
}
}
}
10 changes: 10 additions & 0 deletions src/NSubstitute/Routing/AutoValues/IAutoValueProvidersFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Collections.Generic;
using NSubstitute.Core;

namespace NSubstitute.Routing.AutoValues
{
public interface IAutoValueProvidersFactory
{
IReadOnlyCollection<IAutoValueProvider> CreateProviders(ISubstituteFactory substituteFactory);
}
}

0 comments on commit 6087233

Please sign in to comment.