More unit tests, more code coverage

This commit is contained in:
Antony Male 2014-05-07 17:48:00 +01:00
parent fe377e3955
commit fe13725062
13 changed files with 333 additions and 22 deletions

View File

@ -45,7 +45,7 @@ end
desc "Generate code coverage reports for CONFIG (or Debug)"
task :cover => [:build, COVERAGE_DIR] do |t|
sh OPENCOVER_CONSOLE, %Q{-register:user -target:"#{NUNIT_CONSOLE}" -filter:+[Stylet]* -targetargs:"#{UNIT_TESTS_DLL} /noshadow" -output:"#{COVERAGE_FILE}"}
sh OPENCOVER_CONSOLE, %Q{-register:user -target:"#{NUNIT_CONSOLE}" -filter:"+[Stylet]* -[Stylet]XamlGeneratedNamespace.*" -targetargs:"#{UNIT_TESTS_DLL} /noshadow" -output:"#{COVERAGE_FILE}"}
sh REPORT_GENERATOR, %Q{-reports:"#{COVERAGE_FILE}" "-targetdir:#{COVERAGE_DIR}"}
rm 'TestResult.xml'
end

View File

@ -92,7 +92,7 @@ namespace StyletIoC
var key = ((InjectAttribute)ctorsWithAttribute[0].GetCustomAttribute(typeof(InjectAttribute), false)).Key;
var cantResolve = ctor.GetParameters().Where(p => !this.container.CanResolve(new TypeKey(p.ParameterType, key)) && !p.HasDefaultValue).FirstOrDefault();
if (cantResolve != null)
throw new StyletIoCFindConstructorException(String.Format("Found a constructor with [Inject] on type {0}, but can't resolve parameter '{1}' (which doesn't have a default value).", this.Type.Description(), cantResolve.Name));
throw new StyletIoCFindConstructorException(String.Format("Found a constructor with [Inject] on type {0}, but can't resolve parameter '{1}' (of type {2}, and doesn't have a default value).", this.Type.Description(), cantResolve.Name, cantResolve.ParameterType.Description()));
}
else
{
@ -121,7 +121,7 @@ namespace StyletIoC
}
catch (StyletIoCRegistrationException e)
{
throw new StyletIoCRegistrationException(String.Format("{0} Required by parameter '{1}' of type {2}.", e.Message, x.Name, this.Type.Description()), e);
throw new StyletIoCRegistrationException(String.Format("{0} Required by parameter '{1}' of type {2} (which is a {3}).", e.Message, x.Name, this.Type.Description(), x.ParameterType.Description()), e);
}
}
// For some reason we need this cast...

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -34,6 +35,8 @@ namespace StyletIoC
public IRegistrationCollection AddRegistration(IRegistration registration)
{
if (this.registration.Type == registration.Type)
throw new StyletIoCRegistrationException(String.Format("Multiple registrations for type {0} found.", registration.Type.Description()));
return new RegistrationCollection(new List<IRegistration>() { this.registration, registration });
}
}
@ -64,9 +67,8 @@ namespace StyletIoC
// Need to lock the list, as someone might be fetching from it while we do this
lock (this.registrations)
{
// Is there an existing registration for this type?
if (this.registrations.Any(x => x.Type == registration.Type))
throw new StyletIoCRegistrationException(String.Format("Multiple registrations for type {0} found.", registration.Type.Description()));
// Should have been caught by SingleRegistration.AddRegistration
Debug.Assert(!this.registrations.Any(x => x.Type == registration.Type));
this.registrations.Add(registration);
return this;
}

View File

@ -397,7 +397,14 @@ namespace StyletIoC
internal IRegistrationCollection AddRegistration(TypeKey typeKey, IRegistration registration)
{
return this.registrations.AddOrUpdate(typeKey, x => new SingleRegistration(registration), (x, c) => c.AddRegistration(registration));
try
{
return this.registrations.AddOrUpdate(typeKey, x => new SingleRegistration(registration), (x, c) => c.AddRegistration(registration));
}
catch (StyletIoCRegistrationException e)
{
throw new StyletIoCRegistrationException(String.Format("{0} Service type: {1}, key: '{2}'", e.Message, typeKey.Type.Description(), typeKey.Key), e);
}
}
internal void AddUnboundGeneric(TypeKey typeKey, UnboundGeneric unboundGeneric)
@ -407,7 +414,7 @@ namespace StyletIoC
var unboundGenerics = this.unboundGenerics.GetOrAdd(typeKey, x => new List<UnboundGeneric>());
lock (unboundGenerics)
{
// Is there an auto-registration for this type? If so, remove it
// Is there an existing registration for this type?
if (unboundGenerics.Any(x => x.Type == unboundGeneric.Type))
throw new StyletIoCRegistrationException(String.Format("Multiple registrations for type {0} found", typeKey.Type.Description()));

View File

@ -10,12 +10,7 @@ namespace StyletIoC
internal class UnboundGeneric
{
private StyletIoCContainer container;
public string Key { get; set; }
public Type Type { get; private set; }
public int NumTypeParams
{
get { return this.Type.GetTypeInfo().GenericTypeParameters.Length; }
}
public bool IsSingleton { get; private set; }
public UnboundGeneric(Type type, StyletIoCContainer container, bool isSingleton)

View File

@ -14,7 +14,7 @@ namespace Stylet.Xaml
/// </summary>
public class DebugConverter : DependencyObject, IValueConverter
{
public static readonly DebugConverter Instance = new DebugConverter();
public static readonly DebugConverter Instance;
/// <summary>
/// Category to use with Debug.WriteLine
@ -29,13 +29,41 @@ namespace Stylet.Xaml
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(DebugConverter), new PropertyMetadata("DebugConverter"));
/// <summary>
/// Logger to use. Defaults to Debug.WriteLine. Arguments are: Message, Name
/// </summary>
public Action<string, string> Logger
{
get { return (Action<string, string>)GetValue(LoggerProperty); }
set { SetValue(LoggerProperty, value); }
}
// Using a DependencyProperty as the backing store for Logger. This enables animation, styling, binding, etc...
public static readonly DependencyProperty LoggerProperty =
DependencyProperty.Register("Logger", typeof(Action<string, string>), typeof(DebugConverter), new PropertyMetadata(null));
static DebugConverter()
{
// Have to set this from within a static constructor, as it's run after the field initializers
// Otherwise it gets called before the DependencyProperties have been created, and that causes the (normal) constructor to fall over
Instance = new DebugConverter();
}
public DebugConverter()
{
if (this.Logger == null)
this.Logger = (msg, name) => Debug.WriteLine(msg, name);
}
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (parameter == null)
Debug.WriteLine(String.Format("Convert: Value = '{0}' TargetType = '{1}'", value, targetType), this.Name);
this.Logger(String.Format("Convert: Value = '{0}' TargetType = '{1}'", value, targetType), this.Name);
else
Debug.WriteLine(String.Format("Convert: Value = '{0}' TargetType = '{1}' Parameter = '{2}'", value, targetType, parameter), this.Name);
this.Logger(String.Format("Convert: Value = '{0}' TargetType = '{1}' Parameter = '{2}'", value, targetType, parameter), this.Name);
return value;
}
@ -43,9 +71,9 @@ namespace Stylet.Xaml
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (parameter == null)
Debug.WriteLine(String.Format("ConvertBack: Value = '{0}' TargetType = '{1}'", value, targetType), this.Name);
this.Logger(String.Format("ConvertBack: Value = '{0}' TargetType = '{1}'", value, targetType), this.Name);
else
Debug.WriteLine(String.Format("ConvertBack: Value = '{0}' TargetType = '{1}' Parameter = '{2}'", value, targetType, parameter), this.Name);
this.Logger(String.Format("ConvertBack: Value = '{0}' TargetType = '{1}' Parameter = '{2}'", value, targetType, parameter), this.Name);
return value;
}

View File

@ -0,0 +1,83 @@
using NUnit.Framework;
using Stylet.Xaml;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StyletUnitTests
{
[TestFixture]
public class DebugConverterTests
{
private DebugConverter converter;
private List<string> log;
[SetUp]
public void SetUp()
{
this.log = new List<string>();
this.converter = new DebugConverter();
this.converter.Logger = (msg, name) => log.Add(msg);
}
[Test]
public void InstancePropertyIsSingleton()
{
Assert.AreEqual(DebugConverter.Instance, DebugConverter.Instance);
}
[Test]
public void ConvertPassesThroughValue()
{
var result = this.converter.Convert(5, null, null, null);
Assert.AreEqual(5, result);
}
[Test]
public void ConvertBackPassesThrough()
{
var result = this.converter.ConvertBack("hello", null, null, null);
Assert.AreEqual("hello", result);
}
[Test]
public void NameIsUsedInLogger()
{
this.converter.Logger = (msg, name) => log.Add(name);
this.converter.Name = "Test";
this.converter.Convert(new object(), null, null, null);
Assert.That(this.log, Is.EquivalentTo(new[] { "Test" }));
}
[Test]
public void LogsConvertWithNoParameter()
{
this.converter.Convert(5, typeof(int), null, null);
Assert.That(this.log, Is.EquivalentTo(new[] { "Convert: Value = '5' TargetType = 'System.Int32'" }));
}
[Test]
public void LogsConvertWithParameter()
{
this.converter.Convert("hello", typeof(bool), "the parameter", null);
Assert.That(this.log, Is.EquivalentTo(new[] { "Convert: Value = 'hello' TargetType = 'System.Boolean' Parameter = 'the parameter'" }));
}
[Test]
public void LogsConvertBackWithNoParameter()
{
this.converter.ConvertBack(2.2, typeof(string), null, null);
Assert.That(this.log, Is.EquivalentTo(new[] { "ConvertBack: Value = '2.2' TargetType = 'System.String'" }));
}
[Test]
public void LogsConvertBackWithParameter()
{
this.converter.ConvertBack(false, typeof(double), 5, null);
Assert.That(this.log, Is.EquivalentTo(new[] { "ConvertBack: Value = 'False' TargetType = 'System.Double' Parameter = '5'" }));
}
}
}

View File

@ -0,0 +1,51 @@
using NUnit.Framework;
using StyletIoC;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StyletUnitTests
{
[TestFixture]
public class StyletIoCCompileTests
{
private class C1 { }
private class C2
{
public C2(C1 c1) { }
}
[Test]
public void CompileSucceedsIfNoErrors()
{
var builder = new StyletIoCBuilder();
builder.Bind<C1>().ToSelf();
var ioc = builder.BuildContainer();
Assert.DoesNotThrow(() => ioc.Compile());
Assert.NotNull(ioc.Get<C1>());
}
[Test]
public void CompileThrowsIfFindConstructorExceptionAndThrowOnErrorIsTrue()
{
var builder = new StyletIoCBuilder();
builder.Bind<C2>().ToSelf();
var ioc = builder.BuildContainer();
Assert.Throws<StyletIoCFindConstructorException>(() => ioc.Compile());
}
[Test]
public void CompileDoesNotThrowIfFindConstructorExceptionAndThrowOnErrorIsFalse()
{
var builder = new StyletIoCBuilder();
builder.Bind<C2>().ToSelf();
var ioc = builder.BuildContainer();
Assert.DoesNotThrow(() => ioc.Compile(false));
}
}
}

View File

@ -93,6 +93,13 @@ namespace StyletUnitTests
}
}
class C9
{
public C9(I1 i1)
{
}
}
[TestFixture]
public class StyletIoCConstructorInjectionTests
{
@ -215,5 +222,26 @@ namespace StyletUnitTests
Assert.IsInstanceOf<C1>(i1s[0]);
Assert.IsInstanceOf<C2>(i1s[1]);
}
[Test]
public void ThrowsIfCantResolveAttributedConstructor()
{
var builder = new StyletIoCBuilder();
builder.Bind<C6>().ToSelf();
var ioc = builder.BuildContainer();
Assert.Throws<StyletIoCFindConstructorException>(() => ioc.Get<C6>());
}
[Test]
public void ThrowsIfResolvingParamFailsForSomeReason()
{
var builder = new StyletIoCBuilder();
builder.Bind<I1>().To<C1>();
builder.Bind<I1>().To<C2>();
builder.Bind<C9>().ToSelf();
var ioc = builder.BuildContainer();
Assert.Throws<StyletIoCRegistrationException>(() => ioc.Get<C9>());
}
}
}

View File

@ -35,7 +35,7 @@ namespace StyletUnitTests
var results1 = ioc.GetAll<IC1>().ToList();
var results2 = ioc.GetAll<IC1>().ToList();
Assert.AreEqual(results1.Count, 3);
Assert.AreEqual(3, results1.Count);
Assert.IsInstanceOf<C11>(results1[0]);
Assert.IsInstanceOf<C12>(results1[1]);
@ -57,7 +57,7 @@ namespace StyletUnitTests
var results1 = ioc.GetAll(typeof(IC1)).ToList();
var results2 = ioc.GetAll(typeof(IC1)).ToList();
Assert.AreEqual(results1.Count, 3);
Assert.AreEqual(3, results1.Count);
Assert.IsInstanceOf<C11>(results1[0]);
Assert.IsInstanceOf<C12>(results1[1]);
Assert.IsInstanceOf<C13>(results1[2]);
@ -78,7 +78,7 @@ namespace StyletUnitTests
var results1 = ioc.GetAll<IC1>().ToList();
var results2 = ioc.GetAll<IC1>().ToList();
Assert.AreEqual(results1.Count, 3);
Assert.AreEqual(3, results1.Count);
Assert.IsInstanceOf<C11>(results1[0]);
Assert.IsInstanceOf<C12>(results1[1]);
Assert.IsInstanceOf<C13>(results1[2]);
@ -99,12 +99,78 @@ namespace StyletUnitTests
var results1 = ioc.GetAll(typeof(IC1)).ToList();
var results2 = ioc.GetAll(typeof(IC1)).ToList();
Assert.AreEqual(results1.Count, 3);
Assert.AreEqual(3, results1.Count);
Assert.IsInstanceOf<C11>(results1[0]);
Assert.IsInstanceOf<C12>(results1[1]);
Assert.IsInstanceOf<C13>(results1[2]);
Assert.That(results1, Is.EquivalentTo(results2));
}
[Test]
public void GetAllReturnsSingleInstanceIfOnlyOneRegistration()
{
var builder = new StyletIoCBuilder();
builder.Bind<IC1>().To<C11>();
var ioc = builder.BuildContainer();
var results = ioc.GetAll<IC1>().ToList();
Assert.AreEqual(1, results.Count);
Assert.IsInstanceOf<C11>(results[0]);
}
[Test]
public void GetAllThrowsIfNoRegistrationsFound()
{
var builder = new StyletIoCBuilder();
var ioc = builder.BuildContainer();
Assert.Throws<StyletIoCRegistrationException>(() => ioc.GetAll<IC1>());
}
[Test]
public void GetAllThrowsIfTypeIsNull()
{
var builder = new StyletIoCBuilder();
var ioc = builder.BuildContainer();
Assert.Throws<ArgumentNullException>(() => ioc.GetAll(null));
}
// Also cover GetTypeOrAll here
[Test]
public void GetTypeOrAllReturnsSingleIfOneRegistration()
{
var builder = new StyletIoCBuilder();
builder.Bind<IC1>().To<C11>();
var ioc = builder.BuildContainer();
var result = ioc.GetTypeOrAll<IC1>();
Assert.IsInstanceOf<C11>(result);
}
[Test]
public void GetTypeOrAllReturnsCollectionIfManyRegistrations()
{
var builder = new StyletIoCBuilder();
builder.Bind<IC1>().To<C11>();
builder.Bind<IC1>().To<C12>();
var ioc = builder.BuildContainer();
var result = ioc.GetTypeOrAll<IEnumerable<IC1>>();
Assert.IsInstanceOf<IEnumerable<IC1>>(result);
var list = ((IEnumerable<IC1>)result).ToList();
Assert.AreEqual(2, list.Count);
Assert.IsInstanceOf<C11>(list[0]);
Assert.IsInstanceOf<C12>(list[1]);
}
[Test]
public void GetTypeOrAllThrowsIfTypeIsNull()
{
var builder = new StyletIoCBuilder();
var ioc = builder.BuildContainer();
Assert.Throws<ArgumentNullException>(() => ioc.GetTypeOrAll(null));
}
}
}

View File

@ -13,6 +13,7 @@ namespace StyletUnitTests
{
interface IC1 { }
class C1 : IC1 { }
class C12 : IC1 { }
[Test]
public void SelfTransientBindingResolvesGeneric()
@ -181,5 +182,33 @@ namespace StyletUnitTests
Assert.That(obj1, Is.Not.Null);
Assert.That(obj1, Is.EqualTo(obj2));
}
[Test]
public void ThrowsIfMoreThanOneRegistrationFound()
{
var builder = new StyletIoCBuilder();
builder.Bind<IC1>().To<C1>();
builder.Bind<IC1>().To<C12>();
var ioc = builder.BuildContainer();
Assert.Throws<StyletIoCRegistrationException>(() => ioc.Get<IC1>());
}
[Test]
public void ThrowsIfSameBindingAppearsMultipleTimes()
{
var builder = new StyletIoCBuilder();
builder.Bind<IC1>().To<C1>();
builder.Bind<IC1>().To<C1>();
Assert.Throws<StyletIoCRegistrationException>(() => builder.BuildContainer());
}
[Test]
public void ThrowsIfTypeIsNull()
{
var builder = new StyletIoCBuilder();
var ioc = builder.BuildContainer();
Assert.Throws<ArgumentNullException>(() => ioc.Get(null));
}
}
}

View File

@ -48,5 +48,25 @@ namespace StyletUnitTests
var c2 = ioc.Get<I2<int, bool>>();
Assert.IsInstanceOf<C2<bool, int>>(c2);
}
[Test]
public void ResolvesSingletonUnboundGeneric()
{
var builder = new StyletIoCBuilder();
builder.Bind(typeof(I1<>)).To(typeof(C1<>)).InSingletonScope();
var ioc = builder.BuildContainer();
Assert.AreEqual(ioc.Get<I1<int>>(), ioc.Get<I1<int>>());
}
[Test]
public void ResolvesUnboundGenericFromKey()
{
var builder = new StyletIoCBuilder();
builder.Bind(typeof(I1<>)).To(typeof(C1<>)).WithKey("test");
var ioc = builder.BuildContainer();
Assert.NotNull(ioc.Get<I1<int>>("test"));
}
}
}

View File

@ -59,6 +59,7 @@
<Compile Include="ConductorNavigatingTests.cs" />
<Compile Include="ConductorOneActiveTests.cs" />
<Compile Include="ConductorTests.cs" />
<Compile Include="DebugConverterTests.cs" />
<Compile Include="EventAggregatorTests.cs" />
<Compile Include="ExecuteTests.cs" />
<Compile Include="ExpressionExtensionsTests.cs" />
@ -72,6 +73,7 @@
<Compile Include="ScreenTests.cs" />
<Compile Include="StyletIoC\StyletIoCAutobindingTests.cs" />
<Compile Include="StyletIoC\StyletIoCBindingChecksTests.cs" />
<Compile Include="StyletIoC\StyletIoCCompileTests.cs" />
<Compile Include="StyletIoC\StyletIoCPropertyInjectionTests.cs" />
<Compile Include="StyletIoC\StyletIoCConstructorInjectionTests.cs" />
<Compile Include="StyletIoC\StyletIoCFactoryTests.cs" />