Skip to content

Commit 79981e7

Browse files
committed
Including target complex type constructability in mapping validation
1 parent 839f1e3 commit 79981e7

File tree

2 files changed

+61
-5
lines changed

2 files changed

+61
-5
lines changed

AgileMapper.UnitTests/WhenValidatingMappings.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public void ShouldNotErrorIfCachedMappingMemberIsIgnored()
7272
.From<PublicProperty<string>>().To<PublicField<int>>()
7373
.Ignore(pf => pf.Value);
7474

75-
mapper.GetPlanFor<PublicProperty<string>>().OnTo<PublicField<int>>();
75+
string plan = mapper.GetPlanFor<PublicProperty<string>>().OnTo<PublicField<int>>();
7676

7777
Should.NotThrow(() => mapper.ThrowNowIfAnyMappingPlanIsIncomplete());
7878
}
@@ -106,6 +106,8 @@ public void ShouldErrorIfComplexTypeMemberIsUnconstructable()
106106
mapper.ThrowNowIfAnyMappingPlanIsIncomplete());
107107

108108
validationEx.Message.ShouldContain("PublicField<PublicField<int>> -> PublicProperty<PublicTwoParamCtor<int, int>>");
109+
validationEx.Message.ShouldContain("Unconstructable target Types");
110+
validationEx.Message.ShouldContain("PublicField<int> -> PublicTwoParamCtor<int, int>");
109111
validationEx.Message.ShouldContain("Unmapped target members");
110112
validationEx.Message.ShouldContain("PublicProperty<PublicTwoParamCtor<int, int>>.Value");
111113
}
@@ -145,6 +147,24 @@ public void ShouldErrorIfEnumerableMemberHasNonEnumerableSource()
145147
}
146148
}
147149

150+
[Fact]
151+
public void ShouldErrorIfEnumerableMemberHasUnconstructableElements()
152+
{
153+
using (var mapper = Mapper.CreateNew())
154+
{
155+
mapper
156+
.GetPlanFor<Address[]>()
157+
.ToANew<PublicCtor<string>[]>();
158+
159+
var validationEx = Should.Throw<MappingValidationException>(() =>
160+
mapper.ThrowNowIfAnyMappingPlanIsIncomplete());
161+
162+
validationEx.Message.ShouldContain("Address[] -> PublicCtor<string>[]");
163+
validationEx.Message.ShouldContain("Unconstructable target Types");
164+
validationEx.Message.ShouldContain("Address -> PublicCtor<string>");
165+
}
166+
}
167+
148168
[Fact]
149169
public void ShouldShowMultipleIncompleteCachedMappingPlans()
150170
{

AgileMapper/Validation/MappingValidator.cs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Extensions.Internal;
99
using Members;
1010
using ObjectPopulation;
11+
using ReadableExpressions.Extensions;
1112

1213
internal static class MappingValidator
1314
{
@@ -62,6 +63,7 @@ private static void VerifyMappingPlanIsComplete(IEnumerable<ObjectMapperData> ma
6263
failureMessage
6364
.Append(" Rule set: ").AppendLine(rootData.RuleSet.Name).AppendLine();
6465

66+
AddUnmappableTargetTypesInfo(mappingData.UnmappableTargetTypes, failureMessage);
6567
AddUnmappedTargetMembersInfo(mappingData.UnmappedMembers, failureMessage, rootData);
6668
AddUnpairedEnumsInfo(mappingData.UnpairedEnums, failureMessage);
6769
}
@@ -76,18 +78,26 @@ private static ICollection<IncompleteMappingData> GetIncompleteMappingPlanData(
7678
.Select(md => new
7779
{
7880
MapperData = md,
81+
IsUnmappable =
82+
!md.IsRoot &&
83+
md.TargetMember.IsComplex &&
84+
md.DataSourcesByTargetMember.None(),
7985
UnmappedMembers = md
8086
.DataSourcesByTargetMember
8187
.Where(pair => !pair.Value.HasValue)
8288
.Select(pair => pair)
8389
.ToArray(),
8490
UnpairedEnums = EnumMappingMismatchFinder.FindMismatches(md)
8591
})
86-
.Where(d => d.UnmappedMembers.Any() || d.UnpairedEnums.Any())
92+
.Where(d => d.IsUnmappable || d.UnmappedMembers.Any() || d.UnpairedEnums.Any())
8793
.GroupBy(d => d.MapperData.GetRootMapperData())
8894
.Select(g => new IncompleteMappingData
8995
{
9096
RootMapperData = g.Key,
97+
UnmappableTargetTypes = g
98+
.Where(d => d.IsUnmappable)
99+
.Select(d => d.MapperData)
100+
.ToList(),
91101
UnmappedMembers = g
92102
.SelectMany(d => d.UnmappedMembers)
93103
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value),
@@ -124,6 +134,30 @@ private static void AddMappingTypeHeaderIfRequired(
124134
previousRootMapperData = rootData;
125135
}
126136

137+
private static void AddUnmappableTargetTypesInfo(
138+
ICollection<ObjectMapperData> unmappableTargetTypeData,
139+
StringBuilder failureMessage)
140+
{
141+
if (unmappableTargetTypeData.None())
142+
{
143+
return;
144+
}
145+
146+
failureMessage
147+
.AppendLine(" Unconstructable target Types - fix by ignoring or configuring constructor parameters:")
148+
.AppendLine();
149+
150+
foreach (var unmappableTypeData in unmappableTargetTypeData)
151+
{
152+
var sourceTypeName = unmappableTypeData.SourceType.GetFriendlyName();
153+
var targetTypeName = unmappableTypeData.TargetType.GetFriendlyName();
154+
155+
failureMessage.Append(" - ").Append(sourceTypeName).Append(" -> ").AppendLine(targetTypeName);
156+
}
157+
158+
failureMessage.AppendLine();
159+
}
160+
127161
private static void AddUnmappedTargetMembersInfo(
128162
Dictionary<QualifiedMember, DataSourceSet> unmappedMembers,
129163
StringBuilder failureMessage,
@@ -144,6 +178,8 @@ private static void AddUnmappedTargetMembersInfo(
144178

145179
failureMessage.Append(" - ").AppendLine(targetMemberPath);
146180
}
181+
182+
failureMessage.AppendLine();
147183
}
148184

149185
private static void AddUnpairedEnumsInfo(
@@ -173,16 +209,16 @@ private static void AddUnpairedEnumsInfo(
173209
}
174210

175211
private static IEnumerable<ObjectMapperData> GetAllMapperDatas(IEnumerable<ObjectMapperData> mapperDatas)
176-
{
177-
return mapperDatas.SelectMany(md => md.EnumerateAllMapperDatas());
178-
}
212+
=> mapperDatas.SelectMany(md => md.EnumerateAllMapperDatas());
179213

180214
#region Helper Class
181215

182216
private class IncompleteMappingData
183217
{
184218
public IMemberMapperData RootMapperData { get; set; }
185219

220+
public ICollection<ObjectMapperData> UnmappableTargetTypes { get; set; }
221+
186222
public Dictionary<QualifiedMember, DataSourceSet> UnmappedMembers { get; set; }
187223

188224
public ICollection<EnumMappingMismatchSet> UnpairedEnums { get; set; }

0 commit comments

Comments
 (0)