Skip to content

Commit

Permalink
Merge pull request #26 from Jason-eCargo/master
Browse files Browse the repository at this point in the history
Add generic collection types for AutoSubstitute
  • Loading branch information
robdmoore authored Jan 31, 2017
2 parents 27d9e62 + f258cd8 commit 859370f
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 10 deletions.
153 changes: 153 additions & 0 deletions AutofacContrib.NSubstitute.Tests/AutoSubstituteCollectionFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using NSubstitute;
using NUnit.Framework;

namespace AutofacContrib.NSubstitute.Tests
{
[TestFixture]
public sealed class AutoSubstituteCollectionFixture
{
#region stubs

public interface IServiceItem
{
}

public class ServiceItemA : IServiceItem
{
}

public class ServiceItemB : IServiceItem
{
}

public sealed class TestIEnumerableComponent
{
public readonly IEnumerable<IServiceItem> ServiceItems;

public TestIEnumerableComponent(IEnumerable<IServiceItem> serviceItems)
{
ServiceItems = serviceItems;
}
}

public sealed class TestIListComponent
{
public readonly IList<IServiceItem> ServiceItems;

public TestIListComponent(IList<IServiceItem> serviceItems)
{
ServiceItems = serviceItems;
}
}

public sealed class TestIReadOnlyCollectionComponent
{
public readonly IReadOnlyCollection<IServiceItem> ServiceItems;

public TestIReadOnlyCollectionComponent(IReadOnlyCollection<IServiceItem> serviceItems)
{
ServiceItems = serviceItems;
}
}

public sealed class TestICollectionComponent
{
public readonly ICollection<IServiceItem> ServiceItems;

public TestICollectionComponent(ICollection<IServiceItem> serviceItems)
{
ServiceItems = serviceItems;
}
}

public sealed class TestIReadOnlyListComponent
{
public readonly IReadOnlyList<IServiceItem> ServiceItems;

public TestIReadOnlyListComponent(IReadOnlyList<IServiceItem> serviceItems)
{
ServiceItems = serviceItems;
}
}

#endregion

[Test]
public void TestIEnumerableCorrectlyResolves()
{
using(var autosub = new AutoSubstitute())
{
var mockA = autosub.Provide<IServiceItem, ServiceItemA>();
var mockB = autosub.Provide<IServiceItem, ServiceItemB>();
var component = autosub.Resolve<TestIEnumerableComponent>();

Assert.That(component.ServiceItems, Is.Not.Empty);
Assert.That(component.ServiceItems.Contains(mockA), Is.True);
Assert.That(component.ServiceItems.Contains(mockB), Is.True);
}
}

[Test]
public void TestIListCorrectlyResolves()
{
using(var autosub = new AutoSubstitute())
{
var mockA = autosub.Provide<IServiceItem, ServiceItemA>();
var mockB = autosub.Provide<IServiceItem, ServiceItemB>();
var component = autosub.Resolve<TestIListComponent>();

Assert.That(component.ServiceItems, Is.Not.Empty);
Assert.That(component.ServiceItems.Contains(mockA), Is.True);
Assert.That(component.ServiceItems.Contains(mockB), Is.True);
}
}

[Test]
public void TestIReadOnlyCollectionCorrectlyResolves()
{
using(var autosub = new AutoSubstitute())
{
var mockA = autosub.Provide<IServiceItem, ServiceItemA>();
var mockB = autosub.Provide<IServiceItem, ServiceItemB>();
var component = autosub.Resolve<TestIReadOnlyCollectionComponent>();

Assert.That(component.ServiceItems, Is.Not.Empty);
Assert.That(component.ServiceItems.Contains(mockA), Is.True);
Assert.That(component.ServiceItems.Contains(mockB), Is.True);
}
}

[Test]
public void TestICollectionCorrectlyResolves()
{
using(var autosub = new AutoSubstitute())
{
var mockA = autosub.Provide<IServiceItem, ServiceItemA>();
var mockB = autosub.Provide<IServiceItem, ServiceItemB>();
var component = autosub.Resolve<TestICollectionComponent>();

Assert.That(component.ServiceItems, Is.Not.Empty);
Assert.That(component.ServiceItems.Contains(mockA), Is.True);
Assert.That(component.ServiceItems.Contains(mockB), Is.True);
}
}

[Test]
public void TestIReadOnlyListCorrectlyResolves()
{
using(var autosub = new AutoSubstitute())
{
var mockA = autosub.Provide<IServiceItem, ServiceItemA>();
var mockB = autosub.Provide<IServiceItem, ServiceItemB>();
var component = autosub.Resolve<TestIReadOnlyListComponent>();

Assert.That(component.ServiceItems, Is.Not.Empty);
Assert.That(component.ServiceItems.Contains(mockA), Is.True);
Assert.That(component.ServiceItems.Contains(mockB), Is.True);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="AutoSubstituteCollectionFixture.cs" />
<Compile Include="AutoSubstituteFixture.cs" />
<Compile Include="KeyedRegistrationFixture.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down
32 changes: 22 additions & 10 deletions AutofacContrib.NSubstitute/NSubstituteRegistrationHandler.cs
Original file line number Diff line number Diff line change
@@ -1,51 +1,63 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Autofac;
using Autofac.Builder;
using Autofac.Core;
using Autofac.Features.Indexed;
using NSubstitute;

namespace AutofacContrib.NSubstitute
{
/// <summary> Resolves unknown interfaces and Mocks using the <see cref="Substitute"/>. </summary>
/// <summary> Resolves unknown interfaces and Mocks using the <see cref="Substitute" />. </summary>
internal class NSubstituteRegistrationHandler : IRegistrationSource
{
private static readonly IReadOnlyCollection<Type> GenericCollectionTypes = new List<Type>
{
typeof(IEnumerable<>),
typeof(IList<>),
typeof(IReadOnlyCollection<>),
typeof(ICollection<>),
typeof(IReadOnlyList<>)
};

/// <summary>
/// Retrieve a registration for an unregistered service, to be used
/// by the container.
/// Retrieve a registration for an unregistered service, to be used
/// by the container.
/// </summary>
/// <param name="service">The service that was requested.</param>
/// <param name="registrationAccessor"></param>
/// <returns>
/// Registrations for the service.
/// Registrations for the service.
/// </returns>
public IEnumerable<IComponentRegistration> RegistrationsFor
(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
if (service == null)
throw new ArgumentNullException("service");

var typedService = service as IServiceWithType;
if (typedService == null ||
!typedService.ServiceType.IsInterface ||
typedService.ServiceType.IsGenericType && typedService.ServiceType.GetGenericTypeDefinition() == typeof(IEnumerable<>) ||
IsGenericListOrCollectionInterface(typedService.ServiceType) ||
typedService.ServiceType.IsArray ||
typeof(IStartable).IsAssignableFrom(typedService.ServiceType))
return Enumerable.Empty<IComponentRegistration>();

var rb = RegistrationBuilder.ForDelegate((c, p) => Substitute.For(new[] { typedService.ServiceType }, null))
var rb = RegistrationBuilder.ForDelegate((c, p) => Substitute.For(new[] {typedService.ServiceType}, null))
.As(service)
.InstancePerLifetimeScope();

return new[] { rb.CreateRegistration() };
return new[] {rb.CreateRegistration()};
}

public bool IsAdapterForIndividualComponents
{
get { return false; }
}

private static bool IsGenericListOrCollectionInterface(Type serviceType)
{
return serviceType.IsGenericType && GenericCollectionTypes.Contains(serviceType.GetGenericTypeDefinition());
}
}
}

0 comments on commit 859370f

Please sign in to comment.