Skip to content

Commit 5807095

Browse files
authored
Inline configuration (#32)
* Switching from MappingTypes.Fixed() to MappingTypes<>.Fixed * Lazy-initialising all user configuration objects in UserConfigurationSet * Removing unnecessary calls to ConfigInfo.ForTargetType() * Support for inline-configuring a custom data source in a creation mapping * Support for retrieving an existing inline mapper based on an inline configuration * Support for differing inline configurations when mapping the same source and target types * Support for additions in inline configurations * Test coverage for inline constant value data source configuration * Adding custom ExcludeFromCodeCoverage attribute * Excluding inline-configured settings from subsequent configuration cloning * Test coverage for extending mapper-contextual config with inline config * Support for differentiating inline-configured data source functions / Always creating a new merged MapperContext for inline configurations * Simplifying execution of inline mappings * Test coverage for inline configuration of data source functions / Support for inline-configured merge mapping * Start of test coverage for inline member ignores * Fixing intermitently-passing mapping plan test * Test coverage for configuring conditional member ignores inline * Test coverage for conditional inline data source configuration * Extending conditional inline data source test coverage * Sorting configured member ignores * Fixing configured item ordering, re: derived types, base types and conditions * Only checking configured item conditions if types and members match * Support for replacing a base mapper's member ignore with one in an inline configuration * Test coverage for ignoring members inline by type filter * Support for extending base member ignore filters with inline ignore filters / Fixing ignore filter cloning * Start of test coverage for constructor data source cloning * Test coverage for replacing cloned constructor data sources * Test coverage for configuring constructor data sources inline * Test coverage for replacing a configured constructor data with inline configuration * Test coverage for invalid inline data source and member ignore configuration * Test coverage for invalid inline constructor parameter configuration * Test coverage for unconvertible constant data source inline configuration * Setting core assembly as CLSCompiant - fixes warning in partial trust tests * Extending test coverage for invalid inline data source configuraton * Extending test coverage for cloning object factories * Test coverage for invalid inline member ignores * Test coverage for inline-configured object factories * Extra test coverage for inline object factory configuration * Fixing object factory selection for derived types / Extending inline object factory test coverage * Test coverage for invalid inline object factory configuration * Start of test coverage for inline derived type mapping configuration * Support for switching source and target type context within an inline mapping configuration * Support for inline specification of assemblies to scan for derived types * Start of test coverage for inline enum pairing / Reducing number of new MappingConfigInfos created during configuration * Test coverage for source and target-type-specific enum pairing * Start of test coverage for inline-configured mapping callbacks * Fixing restriction of mapping callbacks by source and target types when mapping to nested members / Test coverage for inline post mapping callback configuration * Test coverage for inline pre member mapping callback configuration / Support for passing inline configuration to Clone() * Support for calling Clone() with a struct * Test coverage for inline pre-mapping and post-member-mapping callback configuration * Support for inline configuration in the static Mapper.Clone method * Start of inline name-matching configuration * Test coverage for inline name matching configuration * Test coverage for inline string formatting configuration * Test coverage for inline identifier configuration * Test coverage for inline object tracking configuration / Improving object tracking configuration conflict detection and error messages * Test coverage for inline map-to-null configuration * Expanding expression equator implementation with tests
1 parent 8b93b57 commit 5807095

File tree

105 files changed

+3782
-713
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+3782
-713
lines changed

AgileMapper.UnitTests.NonParallel/AgileMapper.UnitTests.NonParallel.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
<Compile Include="..\VersionInfo.cs">
7373
<Link>VersionInfo.cs</Link>
7474
</Compile>
75+
<Compile Include="Configuration\Inline\WhenConfiguringDataSourcesInline.cs" />
7576
<Compile Include="Configuration\WhenConfiguringDataSources.cs" />
7677
<Compile Include="Configuration\WhenConfiguringDerivedTypes.cs" />
7778
<Compile Include="Configuration\WhenConfiguringMappingCallbacks.cs" />
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace AgileObjects.AgileMapper.UnitTests.NonParallel.Configuration.Inline
2+
{
3+
using TestClasses;
4+
using Xunit;
5+
6+
public class WhenConfiguringDataSourcesInline : NonParallelTestsBase
7+
{
8+
[Fact]
9+
public void ShouldApplyAConfiguredConstantViaTheInlineStaticApi()
10+
{
11+
TestThenReset(() =>
12+
{
13+
var result = Mapper
14+
.Clone(new PublicPropertyStruct<string> { Value = "Instance fun!" }, cfg => cfg
15+
.Map("Static fun!")
16+
.To(pps => pps.Value));
17+
18+
result.Value.ShouldBe("Static fun!");
19+
});
20+
}
21+
}
22+
}

AgileMapper.UnitTests/AgileMapper.UnitTests.csproj

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,26 @@
8383
<Compile Include="..\VersionInfo.cs">
8484
<Link>VersionInfo.cs</Link>
8585
</Compile>
86+
<Compile Include="Configuration\Inline\InlineMappingExtensions.cs" />
87+
<Compile Include="Configuration\Inline\WhenConfiguringCallbacksInline.cs" />
88+
<Compile Include="Configuration\Inline\WhenConfiguringConstructorDataSourcesInline.cs" />
89+
<Compile Include="Configuration\Inline\WhenConfiguringDataSourcesInline.cs" />
90+
<Compile Include="Configuration\Inline\WhenConfiguringDataSourcesInlineIncorrectly.cs" />
91+
<Compile Include="Configuration\Inline\WhenConfiguringDerivedTypesInline.cs" />
92+
<Compile Include="Configuration\Inline\WhenConfiguringEnumMappingInline.cs" />
93+
<Compile Include="Configuration\Inline\WhenConfiguringNameMatchingInline.cs" />
94+
<Compile Include="Configuration\Inline\WhenConfiguringObjectCreationInline.cs" />
95+
<Compile Include="Configuration\Inline\WhenConfiguringObjectTrackingInline.cs" />
96+
<Compile Include="Configuration\Inline\WhenConfiguringStringFormattingInline.cs" />
97+
<Compile Include="Configuration\Inline\WhenConfiguringTypeIdentifiersInline.cs" />
98+
<Compile Include="Configuration\Inline\WhenIgnoringMembersInline.cs" />
99+
<Compile Include="Configuration\Inline\WhenIgnoringMembersInlineIncorrectly.cs" />
100+
<Compile Include="Configuration\Inline\WhenMappingToNullInline.cs" />
101+
<Compile Include="Extensions\WhenEquatingExpressions.cs" />
102+
<Compile Include="MapperCloning\WhenCloningConstructorDataSources.cs" />
103+
<Compile Include="MapperCloning\WhenCloningMemberIgnores.cs" />
86104
<Compile Include="Configuration\WhenConfiguringObjectTracking.cs" />
87105
<Compile Include="Configuration\WhenConfiguringObjectTrackingIncorrectly.cs" />
88-
<Compile Include="MapperCloning\WhenCloningMapperMemberIgnores.cs" />
89106
<Compile Include="Configuration\WhenConfiguringDerivedTypesIncorrectly.cs" />
90107
<Compile Include="Configuration\WhenConfiguringStringFormatting.cs" />
91108
<Compile Include="Configuration\WhenIgnoringMembersByFilter.cs" />
@@ -97,7 +114,7 @@
97114
<Compile Include="Dictionaries\Configuration\WhenConfiguringNestedDictionaryMapping.cs" />
98115
<Compile Include="Dictionaries\Configuration\WhenConfiguringTargetDictionaryMapping.cs" />
99116
<Compile Include="Dictionaries\WhenCreatingRootDictionaryMembers.cs" />
100-
<Compile Include="MapperCloning\WhenCloningMapperObjectFactories.cs" />
117+
<Compile Include="MapperCloning\WhenCloningObjectFactories.cs" />
101118
<Compile Include="SimpleTypeConversion\WhenConvertingToCharacters.cs" />
102119
<Compile Include="Structs\Configuration\WhenConfiguringStructCreationCallbacks.cs" />
103120
<Compile Include="Structs\Configuration\WhenConfiguringStructDataSources.cs" />
@@ -157,7 +174,7 @@
157174
<Compile Include="TestClasses\Wedding.cs" />
158175
<Compile Include="TestClasses\WeddingDto.cs" />
159176
<Compile Include="WhenAnalysingCollections.cs" />
160-
<Compile Include="MapperCloning\WhenCloningMapperDataSources.cs" />
177+
<Compile Include="MapperCloning\WhenCloningDataSources.cs" />
161178
<Compile Include="WhenFlatteningObjects.cs" />
162179
<Compile Include="Dictionaries\WhenMappingFromDictionaries.cs" />
163180
<Compile Include="Dictionaries\WhenMappingFromDictionaryMembers.cs" />
@@ -241,6 +258,7 @@
241258
<ItemGroup>
242259
<Analyzer Include="..\packages\xunit.analyzers.0.7.0\analyzers\dotnet\cs\xunit.analyzers.dll" />
243260
</ItemGroup>
261+
<ItemGroup />
244262
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
245263
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
246264
<PropertyGroup>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace AgileObjects.AgileMapper.UnitTests.Configuration.Inline
2+
{
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
6+
internal static class InlineMappingExtensions
7+
{
8+
public static IList<MapperContext> InlineContexts(this IMapper mapper)
9+
{
10+
return ((Mapper)mapper).Context.InlineMappers.InlineContexts.ToArray();
11+
}
12+
}
13+
}
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
namespace AgileObjects.AgileMapper.UnitTests.Configuration.Inline
2+
{
3+
using System;
4+
using System.Collections.Generic;
5+
using AgileMapper.Members;
6+
using Shouldly;
7+
using TestClasses;
8+
using Xunit;
9+
10+
public class WhenConfiguringCallbacksInline
11+
{
12+
[Fact]
13+
public void ShouldConfigureExceptionSwallowingInline()
14+
{
15+
using (var mapper = Mapper.CreateNew())
16+
{
17+
var result = mapper
18+
.Map(new Person())
19+
.ToANew<PersonViewModel>(cfg => cfg
20+
.SwallowAllExceptions()
21+
.And
22+
.After
23+
.CreatingInstances
24+
.Call(ctx => FallOver("BANG")));
25+
26+
result.ShouldBeNull();
27+
}
28+
}
29+
30+
[Fact]
31+
public void ShouldConfigureAnExceptionCallbackInline()
32+
{
33+
using (var mapper = Mapper.CreateNew())
34+
{
35+
var thrownData = default(IMappingExceptionData<Person, PersonViewModel>);
36+
37+
mapper
38+
.Map(new Person())
39+
.ToANew<PersonViewModel>(cfg => cfg
40+
.PassExceptionsTo(ctx => SetVariable(ctx, out thrownData))
41+
.And
42+
.After.CreatingInstances
43+
.Call(ctx => FallOver("BOOM")));
44+
45+
thrownData.ShouldNotBeNull();
46+
thrownData.Source.ShouldBeOfType<Person>();
47+
thrownData.Target.ShouldBeOfType<PersonViewModel>();
48+
thrownData.Exception.ShouldNotBeNull();
49+
thrownData.Exception.Message.ShouldBe("BOOM");
50+
}
51+
}
52+
53+
[Fact]
54+
public void ShouldExecuteAPreMappingCallbackInline()
55+
{
56+
using (var mapper = Mapper.CreateNew())
57+
{
58+
var mappedNames = new List<string>();
59+
60+
mapper
61+
.Map(new Person { Name = "Bernie" })
62+
.Over(new PersonViewModel { Name = "Hillary" }, cfg => cfg
63+
.Before.MappingBegins
64+
.Call((s, t) => mappedNames.AddRange(new[] { s.Name, t.Name })));
65+
66+
mappedNames.ShouldNotBeEmpty();
67+
mappedNames.ShouldBe("Bernie", "Hillary");
68+
}
69+
}
70+
71+
[Fact]
72+
public void ShouldExecuteAPostMappingCallbackConditionallyInline()
73+
{
74+
using (var mapper = Mapper.CreateNew())
75+
{
76+
var mappedNames = new List<string>();
77+
78+
mapper
79+
.Map(new PersonViewModel { Name = "Bernie", AddressLine1 = "Narnia" })
80+
.Over(new Person { Name = "Hillary" }, cfg => cfg
81+
.After
82+
.MappingEnds
83+
.If((s, t) => t.GetType() != typeof(Address))
84+
.Call(ctx => mappedNames.AddRange(new[] { ctx.Source.Name, ctx.Target.Name })));
85+
86+
mappedNames.ShouldNotBeEmpty();
87+
mappedNames.ShouldBe("Bernie", "Bernie");
88+
89+
mapper
90+
.Map(new PersonViewModel { Name = "Bernie", AddressLine1 = "Narnia" })
91+
.Over(new Person { Name = "Hillary" }, cfg => cfg
92+
.After
93+
.MappingEnds
94+
.If((s, t) => t.GetType() != typeof(Address))
95+
.Call(ctx => mappedNames.AddRange(new[] { ctx.Source.Name })));
96+
97+
mappedNames.ShouldBe("Bernie", "Bernie", "Bernie");
98+
}
99+
}
100+
101+
[Fact]
102+
public void ShouldExecuteAPreMemberMappingCallbackConditionallyInline()
103+
{
104+
using (var mapper = Mapper.CreateNew())
105+
{
106+
var mappedTargetId = default(Guid);
107+
108+
var noIdSource = new Person { Name = "Dawn" };
109+
110+
mapper.Clone(noIdSource, cfg => cfg
111+
.Before
112+
.Mapping(p => p.Address)
113+
.If(ctx => ctx.Target.Id != default(Guid))
114+
.Call((s, t) => SetVariable(t.Id, out mappedTargetId)));
115+
116+
mappedTargetId.ShouldBeDefault();
117+
118+
var idSource = new Person { Id = Guid.NewGuid() };
119+
120+
mapper.Clone(idSource, cfg => cfg
121+
.Before
122+
.Mapping(p => p.Address)
123+
.If(ctx => ctx.Target.Id != default(Guid))
124+
.Call((s, t) => SetVariable(t.Id, out mappedTargetId)));
125+
126+
mappedTargetId.ShouldBe(idSource.Id);
127+
128+
mapper.InlineContexts().ShouldHaveSingleItem();
129+
}
130+
}
131+
132+
[Fact]
133+
public void ShouldExecuteAPostMemberMappingCallbackConditionallyInline()
134+
{
135+
using (var mapper = Mapper.CreateNew())
136+
{
137+
var mappedAddress = default(Address);
138+
var callbackCalled = false;
139+
140+
var nullAddressNullNameSource = new Person();
141+
var nullAddressNullNameResult = mapper.Clone(nullAddressNullNameSource, cfg => cfg
142+
.After
143+
.Mapping(p => p.Address)
144+
.If((s, p) => (p.Address != null) ? (p.Address.Line1 != null) : (p.Name != null))
145+
.Call((s, t) => SetVariable(t.Address, out mappedAddress).SetVariable(true, out callbackCalled)));
146+
147+
nullAddressNullNameResult.Address.ShouldBeNull();
148+
mappedAddress.ShouldBeNull();
149+
callbackCalled.ShouldBeFalse();
150+
151+
var nullAddressWithNameSource = new Person { Name = "David" };
152+
var nullAddressWithNameResult = mapper.Clone(nullAddressWithNameSource, cfg => cfg
153+
.After
154+
.Mapping(p => p.Address)
155+
.If((s, p) => (p.Address != null) ? (p.Address.Line1 != null) : (p.Name != null))
156+
.Call((s, t) => SetVariable(t.Address, out mappedAddress).SetVariable(true, out callbackCalled)));
157+
158+
nullAddressWithNameResult.Address.ShouldBeNull();
159+
mappedAddress.ShouldBeNull();
160+
callbackCalled.ShouldBeTrue();
161+
162+
callbackCalled = false;
163+
164+
var nullLine1WithNameSource = new Person { Name = "Brent", Address = new Address { Line2 = "City" } };
165+
var nullLine1WithNameResult = mapper.Clone(nullLine1WithNameSource, cfg => cfg
166+
.After
167+
.Mapping(p => p.Address)
168+
.If((s, p) => (p.Address != null) ? (p.Address.Line1 != null) : (p.Name != null))
169+
.Call((s, t) => SetVariable(t.Address, out mappedAddress).SetVariable(true, out callbackCalled)));
170+
171+
nullLine1WithNameResult.Address.ShouldNotBeNull();
172+
mappedAddress.ShouldBeNull();
173+
callbackCalled.ShouldBeFalse();
174+
175+
var withLine1WithNameSource = new Person { Name = "Chris", Address = new Address { Line1 = "Town" } };
176+
var withLine1WithNameResult = mapper.Clone(withLine1WithNameSource, cfg => cfg
177+
.After
178+
.Mapping(p => p.Address)
179+
.If((s, p) => (p.Address != null) ? (p.Address.Line1 != null) : (p.Name != null))
180+
.Call((s, t) => SetVariable(t.Address, out mappedAddress).SetVariable(true, out callbackCalled)));
181+
182+
withLine1WithNameResult.Address.ShouldNotBeNull();
183+
mappedAddress.ShouldNotBeNull();
184+
callbackCalled.ShouldBeTrue();
185+
186+
mapper.InlineContexts().ShouldHaveSingleItem();
187+
}
188+
}
189+
190+
#region Helper Members
191+
192+
private WhenConfiguringCallbacksInline SetVariable<T>(T valueToSet, out T valueCollector)
193+
{
194+
valueCollector = valueToSet;
195+
return this;
196+
}
197+
198+
private static void FallOver(string message) => throw new InvalidOperationException(message);
199+
200+
#endregion
201+
}
202+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
namespace AgileObjects.AgileMapper.UnitTests.Configuration.Inline
2+
{
3+
using System;
4+
using TestClasses;
5+
using Xunit;
6+
7+
public class WhenConfiguringConstructorDataSourcesInline
8+
{
9+
[Fact]
10+
public void ShouldApplyAConfiguredConstantByParameterTypeInline()
11+
{
12+
using (var mapper = Mapper.CreateNew())
13+
{
14+
var result = mapper
15+
.Map(new PublicProperty<Guid> { Value = Guid.NewGuid() })
16+
.ToANew<PublicCtor<string>>(cfg => cfg
17+
.Map("Hello there!")
18+
.ToCtor<string>());
19+
20+
result.Value.ShouldBe("Hello there!");
21+
}
22+
}
23+
24+
[Fact]
25+
public void ShouldExtendConstructorDataSourceConfiguration()
26+
{
27+
using (var mapper = Mapper.CreateNew())
28+
{
29+
mapper.WhenMapping
30+
.From<PublicTwoFieldsStruct<int, int>>()
31+
.To<PublicTwoParamCtor<int, int>>()
32+
.Map(ctx => ctx.Source.Value1 * 2)
33+
.ToCtor("value1");
34+
35+
var result1 = mapper
36+
.Map(new PublicTwoFieldsStruct<int, int> { Value1 = 2, Value2 = 6 })
37+
.ToANew<PublicTwoParamCtor<int, int>>(cfg => cfg
38+
.Map(ctx => ctx.Source.Value2 / 2)
39+
.ToCtor("value2"));
40+
41+
result1.Value1.ShouldBe(4);
42+
result1.Value2.ShouldBe(3);
43+
44+
var result2 = mapper
45+
.Map(new PublicTwoFieldsStruct<int, int> { Value1 = 3, Value2 = 8 })
46+
.ToANew<PublicTwoParamCtor<int, int>>(cfg => cfg
47+
.Map(ctx => ctx.Source.Value2 / 2)
48+
.ToCtor("value2"));
49+
50+
result2.Value1.ShouldBe(6);
51+
result2.Value2.ShouldBe(4);
52+
}
53+
}
54+
55+
[Fact]
56+
public void ShouldReplaceAConfiguredConstructorDataSource()
57+
{
58+
using (var mapper = Mapper.CreateNew())
59+
{
60+
mapper.WhenMapping
61+
.From<PublicProperty<long>>()
62+
.To<PublicCtor<string>>()
63+
.Map((s, t) => s.Value * 2)
64+
.ToCtor<string>();
65+
66+
var moreThanTwoResult = mapper
67+
.Map(new PublicProperty<long> { Value = 3 })
68+
.ToANew<PublicCtor<string>>(cfg => cfg
69+
.Map((s, t) => s.Value > 2 ? 2 : 1)
70+
.ToCtor<string>());
71+
72+
moreThanTwoResult.Value.ShouldBe("2");
73+
74+
var lessThanTwoResult = mapper
75+
.Map(new PublicProperty<long> { Value = 0 })
76+
.ToANew<PublicCtor<string>>(cfg => cfg
77+
.Map((s, t) => s.Value > 2 ? 2 : 1)
78+
.ToCtor<string>());
79+
80+
lessThanTwoResult.Value.ShouldBe("1");
81+
}
82+
}
83+
}
84+
}

0 commit comments

Comments
 (0)