Little bit of work on the unit test coverage

This commit is contained in:
Antony Male 2014-09-11 12:46:59 +01:00
parent 95e52d543d
commit 3887d38a4a
4 changed files with 80 additions and 29 deletions

View File

@ -82,10 +82,7 @@ namespace StyletIoC
private string KeyForParameter(ParameterInfo parameter)
{
var attributes = parameter.GetCustomAttributes(typeof(InjectAttribute));
if (attributes == null)
return null;
var attribute = (InjectAttribute)attributes.FirstOrDefault();
var attribute = parameter.GetCustomAttributes(typeof(InjectAttribute)).FirstOrDefault() as InjectAttribute;
return attribute == null ? null : attribute.Key;
}

View File

@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
@ -133,9 +134,10 @@ namespace StyletIoC
}
}
internal class PerContainerRegistrations : RegistrationBase
internal class PerContainerRegistration : RegistrationBase
{
private readonly IRegistrationContext parentContext;
private readonly string key;
private readonly object instanceFactoryLock = new object();
private Func<IRegistrationContext, object> instanceFactory;
private object instance;
@ -143,10 +145,11 @@ namespace StyletIoC
private static readonly MethodInfo getMethod = typeof(IContainer).GetMethod("Get", new[] { typeof(Type), typeof(string) });
public PerContainerRegistrations(IRegistrationContext parentContext, ICreator creator, Func<IRegistrationContext, object> instanceFactory = null)
public PerContainerRegistration(IRegistrationContext parentContext, ICreator creator, string key, Func<IRegistrationContext, object> instanceFactory = null)
: base(creator)
{
this.parentContext = parentContext;
this.key = key;
this.instanceFactory = instanceFactory;
this.parentContext.Disposing += (o, e) =>
@ -177,34 +180,28 @@ namespace StyletIoC
protected override Func<IRegistrationContext, object> GetGeneratorInternal()
{
// If the context is our parent context, then everything's fine and we can return our instance
// If not, we need to call Get on the current context, and a different instance of us will be invoked again by that
// If not, well, this should never happen. When we're cloned to the new context, we set ourselves up with the new parent
return ctx =>
{
if (ctx != this.parentContext)
{
return ctx.Get(this.Type);
}
else
{
if (this.disposed)
throw new ObjectDisposedException(String.Format("ChildContainer registration for type {0}", this.Type.Description()));
Debug.Assert(ctx == this.parentContext);
if (this.disposed)
throw new ObjectDisposedException(String.Format("ChildContainer registration for type {0}", this.Type.Description()));
if (this.instance != null)
return this.instance;
this.EnsureInstanceFactoryCreated();
var instance = this.instanceFactory(ctx);
Interlocked.CompareExchange(ref this.instance, instance, null);
if (this.instance != null)
return this.instance;
}
this.EnsureInstanceFactoryCreated();
var instance = this.instanceFactory(ctx);
Interlocked.CompareExchange(ref this.instance, instance, null);
return this.instance;
};
}
public override Expression GetInstanceExpression(ParameterExpression registrationContext)
{
// Always synthesize into a method call onto the current context
var call = Expression.Call(registrationContext, getMethod, Expression.Constant(this.Type));
var call = Expression.Call(registrationContext, getMethod, Expression.Constant(this.Type), Expression.Constant(this.key, typeof(string)));
var cast = Expression.Convert(call, this.Type);
return cast;
}
@ -213,7 +210,7 @@ namespace StyletIoC
{
// Ensure the factory's created, and pass it down. This means the work of compiling the creation expression is done once, ever
this.EnsureInstanceFactoryCreated();
return new PerContainerRegistrations(context, this.creator, this.instanceFactory);
return new PerContainerRegistration(context, this.creator, this.key, this.instanceFactory);
}
}
@ -346,7 +343,7 @@ namespace StyletIoC
public IRegistration CloneToContext(IRegistrationContext context)
{
return this;
throw new InvalidOperationException("should not be cloned");
}
}
}

View File

@ -100,7 +100,7 @@ namespace StyletIoC
public static void InPerContainerScope(this IInScope builder)
{
builder.WithRegistrationFactory((ctx, creator, key) => new PerContainerRegistrations(ctx, creator));
builder.WithRegistrationFactory((ctx, creator, key) => new PerContainerRegistration(ctx, creator, key));
}
}

View File

@ -134,7 +134,7 @@ namespace StyletUnitTests
}
[Test]
public void CreatingSameBindingOnParentAndChildCausesMultipleRegistrations()
public void CreatingSameBindingOnParentAndChildCausesMultipleRegistrations_1()
{
var builder = new StyletIoCBuilder();
builder.Bind<I1>().To<C11>();
@ -146,8 +146,8 @@ namespace StyletUnitTests
var r = child.GetAll<I1>();
Assert.AreEqual(2, child.GetAll<I1>().Count());
Assert.AreEqual(1, parent.GetAll<I1>().Count());
Assert.AreEqual(2, child.GetAll<I1>().Count());
}
[Test]
@ -264,6 +264,20 @@ namespace StyletUnitTests
Assert.AreNotEqual(parent.Get<C1>(), child.Get<C1>());
}
[Test]
public void KeyedChildContainerScopeHasOneInstancePerScope()
{
var builder = new StyletIoCBuilder();
builder.Bind<C1>().ToSelf().WithKey("foo").InPerContainerScope();
var parent = builder.BuildContainer();
var child = parent.CreateChildBuilder().BuildContainer();
Assert.AreEqual(parent.Get<C1>("foo"), parent.Get<C1>("foo"));
Assert.AreEqual(child.Get<C1>("foo"), child.Get<C1>("foo"));
Assert.AreNotEqual(parent.Get<C1>("foo"), child.Get<C1>("foo"));
}
[Test]
public void ChildContainerScopeDisposalDisposesCorrectThing()
{
@ -281,5 +295,48 @@ namespace StyletUnitTests
Assert.True(childs.Disposed);
Assert.False(parents.Disposed);
}
[Test]
public void UsingPerContainerRegistrationAfterDisposalPromptsException()
{
var builder = new StyletIoCBuilder();
builder.Bind<C1>().ToSelf().InPerContainerScope();
var ioc = builder.BuildContainer();
ioc.Dispose();
Assert.Throws<ObjectDisposedException>(() => ioc.Get<C1>());
}
[Test]
public void FuncFactoryFetchesInstanceFromCorrectChild()
{
var builder = new StyletIoCBuilder();
builder.Bind<C1>().ToSelf().InPerContainerScope();
var parent = builder.BuildContainer();
var child = parent.CreateChildBuilder().BuildContainer();
var funcFromParent = parent.Get<Func<C1>>();
var funcFromChild = child.Get<Func<C1>>();
Assert.AreEqual(parent.Get<C1>(), funcFromParent());
Assert.AreEqual(child.Get<C1>(), funcFromChild());
}
[Test]
public void FuncFactoryWithKeyFetchesInstanceFromCorrectChild()
{
var builder = new StyletIoCBuilder();
builder.Bind<C1>().ToSelf().WithKey("foo").InPerContainerScope();
var parent = builder.BuildContainer();
var child = parent.CreateChildBuilder().BuildContainer();
var funcFromParent = parent.Get<Func<string, C1>>();
var funcFromChild = child.Get<Func<string, C1>>();
Assert.AreEqual(parent.Get<C1>("foo"), funcFromParent("foo"));
Assert.AreEqual(child.Get<C1>("foo"), funcFromChild("foo"));
}
}
}