1+ using FluentAssertions ;
2+ using Microsoft . Extensions . DependencyInjection ;
3+ using ProjectR . DI ;
4+ using ProjectR . Services ;
5+ using System . Reflection ;
6+ using Xunit ;
7+
8+ namespace ProjectR . Tests . DI ;
9+
10+ public class MapperRegistrationExtensionsTests
11+ {
12+ private class TestEntity { }
13+ private class TestDto { }
14+ private class TestEntity2 { }
15+ private class TestDto2 { }
16+
17+ private class TestMapper : Mapper < TestEntity , TestDto >
18+ {
19+ public override TestDto Project ( TestEntity source ) => new TestDto ( ) ;
20+ public override TestEntity Build ( TestDto dto ) => new TestEntity ( ) ;
21+ public override void Apply ( TestDto dto , TestEntity entityToUpdate ) { }
22+ }
23+
24+ private class TestMapper2 : Mapper < TestEntity2 , TestDto2 >
25+ {
26+ public override TestDto2 Project ( TestEntity2 source ) => new TestDto2 ( ) ;
27+ public override TestEntity2 Build ( TestDto2 dto ) => new TestEntity2 ( ) ;
28+ public override void Apply ( TestDto2 dto , TestEntity2 entityToUpdate ) { }
29+ }
30+
31+ private abstract class AbstractMapper : Mapper < TestEntity , TestDto >
32+ {
33+ // Abstract class should be ignored during scanning
34+ }
35+
36+ private class NonMapperClass { }
37+
38+ public class MapperRegistryTests
39+ {
40+ [ Fact ]
41+ public void Constructor_WithAssemblyContainingMappers_FindsMappers ( )
42+ {
43+ // Arrange
44+ var assembly = Assembly . GetExecutingAssembly ( ) ;
45+
46+ // Act
47+ var registry = new MapperRegistrationExtensions . MapperRegistry ( new [ ] { assembly } ) ;
48+
49+ // Assert
50+ registry . FoundMappers . Should ( ) . NotBeEmpty ( ) ;
51+ registry . FoundMappers . Should ( ) . Contain ( typeof ( TestMapper ) ) ;
52+ registry . FoundMappers . Should ( ) . Contain ( typeof ( TestMapper2 ) ) ;
53+ }
54+
55+ [ Fact ]
56+ public void Constructor_WithAssemblyContainingMappers_IgnoresAbstractMappers ( )
57+ {
58+ // Arrange
59+ var assembly = Assembly . GetExecutingAssembly ( ) ;
60+
61+ // Act
62+ var registry = new MapperRegistrationExtensions . MapperRegistry ( new [ ] { assembly } ) ;
63+
64+ // Assert
65+ registry . FoundMappers . Should ( ) . NotContain ( typeof ( AbstractMapper ) ) ;
66+ }
67+
68+ [ Fact ]
69+ public void Constructor_WithAssemblyContainingMappers_IgnoresNonMappers ( )
70+ {
71+ // Arrange
72+ var assembly = Assembly . GetExecutingAssembly ( ) ;
73+
74+ // Act
75+ var registry = new MapperRegistrationExtensions . MapperRegistry ( new [ ] { assembly } ) ;
76+
77+ // Assert
78+ registry . FoundMappers . Should ( ) . NotContain ( typeof ( NonMapperClass ) ) ;
79+ registry . FoundMappers . Should ( ) . NotContain ( typeof ( string ) ) ;
80+ }
81+
82+ [ Fact ]
83+ public void Constructor_WithEmptyAssemblyList_ReturnsEmptyCollection ( )
84+ {
85+ // Arrange
86+ var assemblies = Array . Empty < Assembly > ( ) ;
87+
88+ // Act
89+ var registry = new MapperRegistrationExtensions . MapperRegistry ( assemblies ) ;
90+
91+ // Assert
92+ registry . FoundMappers . Should ( ) . BeEmpty ( ) ;
93+ }
94+
95+ [ Fact ]
96+ public void FoundMappers_IsReadOnlyCollection ( )
97+ {
98+ // Arrange
99+ var assembly = Assembly . GetExecutingAssembly ( ) ;
100+ var registry = new MapperRegistrationExtensions . MapperRegistry ( new [ ] { assembly } ) ;
101+
102+ // Act & Assert
103+ registry . FoundMappers . Should ( ) . BeAssignableTo < IReadOnlyCollection < Type > > ( ) ;
104+ }
105+ }
106+
107+ public class AddMappersExtensionTests
108+ {
109+ [ Fact ]
110+ public void AddMappers_WithValidAssembly_RegistersAllServices ( )
111+ {
112+ // Arrange
113+ var services = new ServiceCollection ( ) ;
114+ var assembly = Assembly . GetExecutingAssembly ( ) ;
115+
116+ // Act
117+ services . AddMappers ( assembly ) ;
118+ var serviceProvider = services . BuildServiceProvider ( ) ;
119+
120+ // Assert
121+ // Check that MapperTypeCache is registered
122+ var cache = serviceProvider . GetService < MapperTypeCache > ( ) ;
123+ cache . Should ( ) . NotBeNull ( ) ;
124+
125+ // Check that IMapperResolver is registered
126+ var resolver = serviceProvider . GetService < IMapperResolver > ( ) ;
127+ resolver . Should ( ) . NotBeNull ( ) ;
128+ resolver . Should ( ) . BeOfType < MapperResolver > ( ) ;
129+
130+ // Check that individual mappers are registered
131+ var mapper1 = serviceProvider . GetService < TestMapper > ( ) ;
132+ mapper1 . Should ( ) . NotBeNull ( ) ;
133+
134+ var mapper2 = serviceProvider . GetService < TestMapper2 > ( ) ;
135+ mapper2 . Should ( ) . NotBeNull ( ) ;
136+ }
137+
138+ [ Fact ]
139+ public void AddMappers_WithNullAssemblies_UsesCallingAssembly ( )
140+ {
141+ // Arrange
142+ var services = new ServiceCollection ( ) ;
143+
144+ // Act
145+ services . AddMappers ( null ! ) ;
146+ var serviceProvider = services . BuildServiceProvider ( ) ;
147+
148+ // Assert
149+ var resolver = serviceProvider . GetService < IMapperResolver > ( ) ;
150+ resolver . Should ( ) . NotBeNull ( ) ;
151+ }
152+
153+ [ Fact ]
154+ public void AddMappers_WithEmptyAssemblies_UsesCallingAssembly ( )
155+ {
156+ // Arrange
157+ var services = new ServiceCollection ( ) ;
158+
159+ // Act
160+ services . AddMappers ( ) ;
161+ var serviceProvider = services . BuildServiceProvider ( ) ;
162+
163+ // Assert
164+ var resolver = serviceProvider . GetService < IMapperResolver > ( ) ;
165+ resolver . Should ( ) . NotBeNull ( ) ;
166+ }
167+
168+ [ Fact ]
169+ public void AddMappers_ReturnsServiceCollection_ForChaining ( )
170+ {
171+ // Arrange
172+ var services = new ServiceCollection ( ) ;
173+ var assembly = Assembly . GetExecutingAssembly ( ) ;
174+
175+ // Act
176+ var result = services . AddMappers ( assembly ) ;
177+
178+ // Assert
179+ result . Should ( ) . BeSameAs ( services ) ;
180+ }
181+
182+ [ Fact ]
183+ public void AddMappers_RegistersMapperTypeCacheAsSingleton ( )
184+ {
185+ // Arrange
186+ var services = new ServiceCollection ( ) ;
187+ var assembly = Assembly . GetExecutingAssembly ( ) ;
188+
189+ // Act
190+ services . AddMappers ( assembly ) ;
191+ var serviceProvider = services . BuildServiceProvider ( ) ;
192+
193+ // Assert
194+ var cache1 = serviceProvider . GetService < MapperTypeCache > ( ) ;
195+ var cache2 = serviceProvider . GetService < MapperTypeCache > ( ) ;
196+ cache1 . Should ( ) . BeSameAs ( cache2 ) ;
197+ }
198+
199+ [ Fact ]
200+ public void AddMappers_RegistersIndividualMappersAsSingletons ( )
201+ {
202+ // Arrange
203+ var services = new ServiceCollection ( ) ;
204+ var assembly = Assembly . GetExecutingAssembly ( ) ;
205+
206+ // Act
207+ services . AddMappers ( assembly ) ;
208+ var serviceProvider = services . BuildServiceProvider ( ) ;
209+
210+ // Assert
211+ var mapper1a = serviceProvider . GetService < TestMapper > ( ) ;
212+ var mapper1b = serviceProvider . GetService < TestMapper > ( ) ;
213+ mapper1a . Should ( ) . BeSameAs ( mapper1b ) ;
214+ }
215+
216+ [ Fact ]
217+ public void AddMappers_RegistersResolverAsSingleton ( )
218+ {
219+ // Arrange
220+ var services = new ServiceCollection ( ) ;
221+ var assembly = Assembly . GetExecutingAssembly ( ) ;
222+
223+ // Act
224+ services . AddMappers ( assembly ) ;
225+ var serviceProvider = services . BuildServiceProvider ( ) ;
226+
227+ // Assert
228+ var resolver1 = serviceProvider . GetService < IMapperResolver > ( ) ;
229+ var resolver2 = serviceProvider . GetService < IMapperResolver > ( ) ;
230+ resolver1 . Should ( ) . BeSameAs ( resolver2 ) ;
231+ }
232+ }
233+ }
0 commit comments