Skip to content

Commit 0197dd7

Browse files
committed
Support named generics, fixes #32
1 parent 7c374a0 commit 0197dd7

File tree

2 files changed

+72
-50
lines changed

2 files changed

+72
-50
lines changed

FluentAssertions.Autofac.Tests/RegisterGenericSourceAssertions_Should.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,21 @@ public void Register_Generic()
2323
.SingleInstance();
2424
}
2525

26+
[Fact]
27+
public void Register_Named_Generic()
28+
{
29+
var containerShouldHave = GetSut(builder =>
30+
builder.RegisterGeneric(typeof(Repository<>))
31+
.Named("awesomeRepo", typeof(IRepository<>))
32+
.SingleInstance()
33+
);
34+
35+
containerShouldHave
36+
.RegisteredGeneric(typeof(Repository<>))
37+
.Named("awesomeRepo", typeof(IRepository<>))
38+
.SingleInstance();
39+
}
40+
2641
[Fact]
2742
public void Register_Generic_WithMultiple_GenericArgumentTypes()
2843
{

FluentAssertions.Autofac/RegisterGenericSourceAssertions.cs

Lines changed: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace FluentAssertions.Autofac;
1919
public class
2020
RegisterGenericSourceAssertions : ReferenceTypeAssertions<IComponentContext, RegisterGenericSourceAssertions>
2121
{
22-
private readonly Type _genericComponentTypeDefinition;
22+
private readonly Type _type;
2323

2424
/// <inheritdoc />
2525
/// <summary>
@@ -31,67 +31,74 @@ public class
3131
/// <summary>
3232
/// Initializes a new instance of the <see cref="RegisterGenericSourceAssertions" /> class.
3333
/// </summary>
34-
/// <param name="subject">The container</param>
35-
/// <param name="genericComponentTypeDefinition">The type that should be registered on the container</param>
36-
public RegisterGenericSourceAssertions(IComponentContext subject, Type genericComponentTypeDefinition) :
34+
/// <param name="subject">The component context</param>
35+
/// <param name="type">The type that should be registered on the container</param>
36+
public RegisterGenericSourceAssertions(IComponentContext subject, Type type) :
3737
base(subject)
3838
{
39-
AssertGenericType(genericComponentTypeDefinition);
40-
_genericComponentTypeDefinition = genericComponentTypeDefinition;
39+
AssertGenericType(type);
40+
_type = type;
4141
}
4242

4343
/// <summary>
4444
/// Asserts that the specified service type can be resolved from the current <see cref="IComponentContext" />.
4545
/// </summary>
46-
/// <param name="genericServiceTypeDefinition">The type to resolve</param>
47-
public RegistrationAssertions As(Type genericServiceTypeDefinition)
46+
/// <param name="type">The type to resolve</param>
47+
public RegistrationAssertions As(Type type)
4848
{
49-
AssertGenericType(genericServiceTypeDefinition);
50-
var componentServicePairText =
51-
$"Component={_genericComponentTypeDefinition.FullName} Service={genericServiceTypeDefinition.FullName}";
52-
53-
_genericComponentTypeDefinition.GetGenericArguments().Length.Should()
54-
.Be(genericServiceTypeDefinition.GetGenericArguments().Length,
55-
$"the generic arguments count of both generic component and generic service must be equal. {componentServicePairText}.");
56-
57-
var argumentTypes = Enumerable.Repeat(typeof(object),
58-
_genericComponentTypeDefinition.GetGenericArguments().Length).ToArray();
59-
var componentType = _genericComponentTypeDefinition.MakeGenericType(argumentTypes);
60-
var serviceType = genericServiceTypeDefinition.MakeGenericType(argumentTypes);
49+
var serviceType = GenericServiceTypeFor(type, out var componentType);
50+
var service = new TypedService(serviceType);
51+
var registration = RegistrationFor(type, service, componentType);
52+
return new RegistrationAssertions(Subject, registration);
53+
}
6154

62-
componentType.Should()
63-
.Implement(serviceType,
64-
$"component must implement specified service. {componentServicePairText}.");
55+
/// <summary>
56+
/// Asserts that the specified service type can be resolved from the current <see cref="IComponentContext" />.
57+
/// </summary>
58+
/// <param name="serviceName">The service name</param>
59+
/// <param name="type">The type to resolve</param>
60+
public RegistrationAssertions Named(string serviceName, Type type)
61+
{
62+
var serviceType = GenericServiceTypeFor(type, out var componentType);
63+
var service = new KeyedService(serviceName, serviceType);
64+
var registration = RegistrationFor(type, service, componentType);
65+
return new RegistrationAssertions(Subject, registration);
66+
}
6567

66-
var registration = GetRegistrationFromSources(serviceType);
68+
private IComponentRegistration RegistrationFor(Type type, Service service, Type componentType)
69+
{
70+
var registration = RegistrationsFor(service).FirstOrDefault();
6771
registration.Should()
68-
.NotBeNull(
69-
$"it must be a registration source providing registrations for service {genericServiceTypeDefinition.FullName}");
70-
71-
registration.Activator.LimitType.Should()
72-
.Be(componentType,
73-
$"the generic component type definition in the registration must be {_genericComponentTypeDefinition.FullName}.");
74-
75-
return new RegistrationAssertions(Subject, registration);
72+
.NotBeNull($"there should be a registration source providing registrations for service {type.FullName}");
73+
registration?.Activator.LimitType.Should()
74+
.Be(componentType, $"the generic component type definition registered should be {_type.FullName}.");
75+
return registration;
7676
}
7777

78-
private IComponentRegistration GetRegistrationFromSources(Type serviceType)
78+
private Type GenericServiceTypeFor(Type type, out Type componentType)
7979
{
80-
var typedService = new TypedService(serviceType);
80+
AssertGenericType(type);
81+
var componentServicePairText =
82+
$"Component={_type.FullName} Service={type.FullName}";
8183

82-
foreach (var registrationSource in Subject.ComponentRegistry.Sources)
83-
{
84-
var registration = registrationSource
85-
.RegistrationsFor(typedService, Accessor)
86-
.FirstOrDefault();
84+
_type.GetGenericArguments().Should().HaveCount(type.GetGenericArguments().Length,
85+
$"the generic arguments count of both generic component and generic service must be equal. {componentServicePairText}.");
8786

88-
if (registration != null)
89-
{
90-
return registration;
91-
}
92-
}
87+
var argumentTypes = Enumerable.Repeat(typeof(object),
88+
_type.GetGenericArguments().Length).ToArray();
89+
componentType = _type.MakeGenericType(argumentTypes);
90+
var serviceType = type.MakeGenericType(argumentTypes);
91+
92+
componentType.Should().Implement(serviceType,
93+
$"component must implement specified service. {componentServicePairText}.");
94+
return serviceType;
95+
}
9396

94-
return null;
97+
private IEnumerable<IComponentRegistration> RegistrationsFor(Service service)
98+
{
99+
return Subject.ComponentRegistry.Sources
100+
.SelectMany(sources => sources.RegistrationsFor(service, Accessor)
101+
.ToList());
95102
}
96103

97104
private IEnumerable<ServiceRegistration> Accessor(Service service)
@@ -100,15 +107,15 @@ private IEnumerable<ServiceRegistration> Accessor(Service service)
100107
.Select(c => new ServiceRegistration(ServicePipelines.DefaultServicePipeline, c));
101108
}
102109

103-
private static void AssertGenericType(Type genericTypeDefinition)
110+
private static void AssertGenericType(Type type)
104111
{
105-
if (genericTypeDefinition == null)
106-
throw new ArgumentNullException(nameof(genericTypeDefinition));
112+
if (type == null)
113+
throw new ArgumentNullException(nameof(type));
107114

108-
if (!genericTypeDefinition.IsGenericTypeDefinition)
115+
if (!type.IsGenericTypeDefinition)
109116
{
110117
throw new ArgumentException("Type must be a generic type definition.",
111-
nameof(genericTypeDefinition));
118+
nameof(type));
112119
}
113120
}
114121
}

0 commit comments

Comments
 (0)