Skip to content

Commit 1056f58

Browse files
authored
Releases/1.5 (#161)
* Bugs/unused constructor members (#140) * Adding intermediate-step ConstructionInfos to determine constructability without always creating the construction Expression * Checking object constructability using ConstructionInfos * Tidying * - Populating members with a matching constructor parameter that might not be used - Respecting single-data-source population conditions for readonly member populations * Fixing mapping validation detection of unconstructable members * Updating version numbers * Features/root enum pairing (#141) * Support for root enum pairing * Test coverage for nullable target enums and out-of-range source enum values * Test coverage for root enum mapping * Support for mapping callbacks around root enum mapping * Support for mapping (not projecting) queryables (#142) * v1.5 preview 1 release notes and NuGet package * Features/entity key mapping refinements (#144) * Always allowing entity key mapping in projections * Allowing entity key mapping for view models and DTOs * Handling null nested members in .ToTarget() data sources, fixes #145 * Bugs/issue146 (#146, #147) * Taking a source interface's implemented interfaces into account when matching source members * Test coverage for configured interface source member * Mapping to target interface members' implemented interface members, re: #146 * Features/coverage optimisations (#148) * Removing unused dictionary member population code and optimising * QueryString class test coverage * Optimising DictionaryTargetMember.TryGetMappingBody, IList.Append(IList) and MappingFactory.UseLocalValueVariable * Tidying * Removing unused code * Test coverage for ExpressionInfoFinder index logic * Extending array index data source code coverage * Extending test coverage for index expression data sources * Using instance mapper * Updating to v2.3.1 of ReadableExpressions Removing Index tests from .NET 3.5 tests * Adding coverage TODOs * Increasing data source reversal test coverage / Lazy-loading ExpressionInfoFinder collection members * Fixing reverse data source test coverage * Increasing code coverage / Removing unused or obselete code * Updating to v1.5-preview2 * v1.5-preview 2 NuGet package * Allowing configured condition type tests if mapping from an interface, re: #146 * Support for custom DateTime format strings with nullable DateTimes, re #149 (#150) * Accounting for a conflicting member check being checked against QualifedMember.All - fixes #152 * Support for zero-configuration mapping of interfaces to strings, fixes #153 * Updating to preview3, updating release notes, adding NuGet package * Bugs/simple to complex to target (#154) * ToTarget changes * Tidying * Removing Newtonsoft dependency * Optimising deep clone member-matching * Support for simple type to enumerable ToTarget data sources * Tidying * Fixing tests * Features/tidying (#156) * Updating ReadableExpressions to v2.3.2 * Tidying * Moving member population logic into MemberPopulator from DataSourceSet and MemberPopulationFactory * Optimising Array Prepend + Append calls * Organising fallback data sources * Moving logic into EnumerableTypeHelper * Avoiding yielding null expressions from population factory * Tidying * Tidying * Features/data source improvements (#158) * Renames * Creating DataSourceSets to generate root mapping Expressions * Removing unused MappingExpressionFactory code * Removing ExpressionFactory singleton instances * Switching DataSourceFactory to a delegate * Adding ComplexTypeDataSource factory methods * Start of generating derived type mappings via data sources * Rearranging derived type mapping generation * Adding condition-or-default helper method * Handling unconditional derived type mappings * Detecting derived new element mappings * Fixing derived type mapping, all tests pass! * Organising data source factory files * Features/ignore data sources (#160) * Support for ignoring a given source member Tidying * Reusing created variable value * Switching single-method interfaces to delegates * Features/member population context (#159) * Reusing created variable value * Switching single-method interfaces to delegates * Adding MemberPopulationContext * Avoiding capture creation in .Project() * Avoiding capture creation in .Filter() * Avoiding closure creation in .FirstOrDefault() * Avoiding closure creation in .First() * Reusing MemberPopulationContext and DataSourceFindContext throughout complex type member population creation * Start of SourceMemberMatchContext Tidying * Adding reuseable SourceMemberMatchContext * Tidying * Support for conditional member ignores * Erroring if redundant source ignore configured * Support for all-target source member ignores / Test coverage for ignoring a write-only source member * Invalid configuration test coverage * Fixing configured source member ignore conflict detection * Extra test coverage * Extending test coverage * Support for extending source ignores in inline configuration * Test coverage for incorrect inline source ignore configuration * Start of support for ignoring source members by filter * Support for ignoring source members by filter * Erroring if invalid source member filters are specified * Extending test coverage for global source filters * Support for maptime ignoring of source members by derived type * Splitting source member ignore classes * Splitting target member ignore classes * Renaming ignore classes * Moving shared member ignore logic into interface extension methods * Optimising single-value DataSourceSets Renames * Basic source value filter support * Support for global object-value filters * Test coverage for multi-clause global typed source value filter * Extending test coverage * Renames * Support for filtering simple type source enumerable element values * Extending test coverage * Test coverage for filtering a simple type configured data source * Updating test * Not falling back to a default data source if a configured data source has no default matching source member * Optimising source value filter creation * Tidying * Support for maptime-checked derived source type filters * Test coverage for source value filter-ignored runtime typed derived sources * Extending test coverage * Support for inline-configured source value filters and overlapping multiple source value filters * Removing duplicate filter application / Start of handling null nested members in value filter expressions * Support for nested access checking in source value filters * Support for combining conditional data sources with inline source value filters * Erroring if duplicate source value filters are defined * Erroring if empty source filter configured * Extra test coverage * Support for conditional source value filters using the If() syntax * Organising source value filter classes * Adding / updating documentation * Updating release notes * Updating to v1.5 * Adding v1.5 NuGet package
1 parent e4777d6 commit 1056f58

File tree

247 files changed

+9760
-3516
lines changed

Some content is hidden

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

247 files changed

+9760
-3516
lines changed

AgileMapper.PerformanceTester.Net45/AgileMapper.PerformanceTester.Net45.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@
3737
<Reference Include="AgileObjects.NetStandardPolyfills, Version=1.4.0.0, Culture=neutral, PublicKeyToken=06131ac1c008ad4e, processorArchitecture=MSIL">
3838
<HintPath>..\packages\AgileObjects.NetStandardPolyfills.1.4.0\lib\net40\AgileObjects.NetStandardPolyfills.dll</HintPath>
3939
</Reference>
40-
<Reference Include="AgileObjects.ReadableExpressions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=9f54ad81db69da8e, processorArchitecture=MSIL">
41-
<HintPath>..\packages\AgileObjects.ReadableExpressions.2.1.1\lib\net40\AgileObjects.ReadableExpressions.dll</HintPath>
40+
<Reference Include="AgileObjects.ReadableExpressions, Version=2.3.2.0, Culture=neutral, PublicKeyToken=9f54ad81db69da8e, processorArchitecture=MSIL">
41+
<HintPath>..\packages\AgileObjects.ReadableExpressions.2.3.2\lib\net40\AgileObjects.ReadableExpressions.dll</HintPath>
4242
</Reference>
4343
<Reference Include="AutoMapper, Version=7.0.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
4444
<HintPath>..\packages\AutoMapper.7.0.1\lib\net45\AutoMapper.dll</HintPath>

AgileMapper.PerformanceTester.Net45/packages.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<packages>
33
<package id="AgileObjects.NetStandardPolyfills" version="1.4.0" targetFramework="net452" />
4-
<package id="AgileObjects.ReadableExpressions" version="2.1.1" targetFramework="net452" />
4+
<package id="AgileObjects.ReadableExpressions" version="2.3.2" targetFramework="net452" />
55
<package id="AutoMapper" version="7.0.1" targetFramework="net452" />
66
<package id="Expressmapper" version="1.9.1" targetFramework="net452" />
77
<package id="Mapster" version="3.3.1" targetFramework="net452" />

AgileMapper.UnitTests.Common/ShouldExtensions.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ public static void ShouldBe<TActual, TExpected>(this TActual value, TExpected ex
5252
{
5353
if (!AreEqual(expectedValue, value))
5454
{
55-
Asplode(expectedValue.ToString(), value?.ToString());
55+
Asplode(
56+
expectedValue?.ToString() ?? (typeof(TExpected).CanBeNull() ? "null" : "default"),
57+
value?.ToString() ?? (typeof(TActual).CanBeNull() ? "null" : "default"));
5658
}
5759
}
5860

@@ -405,14 +407,18 @@ public static IDictionary<TKey, TValue> ShouldContainKeyAndValue<TKey, TValue>(
405407
return dictionary;
406408
}
407409

408-
public static void ShouldBeOfType<TExpected>(this object actual)
410+
public static TExpected ShouldBeOfType<TExpected>(this object actual)
409411
{
410-
if (!(actual is TExpected))
412+
if (actual is TExpected expected)
411413
{
412-
Asplode(
413-
"An object of type " + typeof(TExpected).GetFriendlyName(),
414-
actual.GetType().GetFriendlyName());
414+
return expected;
415415
}
416+
417+
Asplode(
418+
"An object of type " + typeof(TExpected).GetFriendlyName(),
419+
actual.GetType().GetFriendlyName());
420+
421+
return default(TExpected);
416422
}
417423

418424
public static void ShouldContain<T>(this IList<T> actual, T expected)

AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj

Lines changed: 595 additions & 4 deletions
Large diffs are not rendered by default.

AgileMapper.UnitTests.Net35/packages.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<packages>
33
<package id="AgileObjects.NetStandardPolyfills" version="1.4.0" targetFramework="net35" />
4-
<package id="AgileObjects.ReadableExpressions" version="2.1.1" targetFramework="net35" />
4+
<package id="AgileObjects.ReadableExpressions" version="2.3.2" targetFramework="net35" />
55
<package id="DynamicLanguageRuntime" version="1.1.2" targetFramework="net35" />
66
<package id="NUnit" version="3.6.1" targetFramework="net35" />
77
<package id="NUnit3TestAdapter" version="3.10.0" targetFramework="net35" />

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@
4242
<Reference Include="AgileObjects.NetStandardPolyfills, Version=1.4.0.0, Culture=neutral, PublicKeyToken=06131ac1c008ad4e, processorArchitecture=MSIL">
4343
<HintPath>..\packages\AgileObjects.NetStandardPolyfills.1.4.0\lib\net40\AgileObjects.NetStandardPolyfills.dll</HintPath>
4444
</Reference>
45-
<Reference Include="AgileObjects.ReadableExpressions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=9f54ad81db69da8e, processorArchitecture=MSIL">
46-
<HintPath>..\packages\AgileObjects.ReadableExpressions.2.1.1\lib\net40\AgileObjects.ReadableExpressions.dll</HintPath>
45+
<Reference Include="AgileObjects.ReadableExpressions, Version=2.3.2.0, Culture=neutral, PublicKeyToken=9f54ad81db69da8e, processorArchitecture=MSIL">
46+
<HintPath>..\packages\AgileObjects.ReadableExpressions.2.3.2\lib\net40\AgileObjects.ReadableExpressions.dll</HintPath>
4747
</Reference>
4848
<Reference Include="System" />
4949
<Reference Include="System.Core" />

AgileMapper.UnitTests.NonParallel/packages.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<packages>
33
<package id="AgileObjects.NetStandardPolyfills" version="1.4.0" targetFramework="net461" />
4-
<package id="AgileObjects.ReadableExpressions" version="2.1.1" targetFramework="net461" />
4+
<package id="AgileObjects.ReadableExpressions" version="2.3.2" targetFramework="net461" />
55
<package id="xunit" version="2.4.1" targetFramework="net461" />
66
<package id="xunit.abstractions" version="2.0.3" targetFramework="net461" />
77
<package id="xunit.analyzers" version="0.10.0" targetFramework="net461" />

AgileMapper.UnitTests.Orms.EfCore2/WhenCreatingProjections.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
namespace AgileObjects.AgileMapper.UnitTests.Orms.EfCore2
22
{
3+
using System.Collections.Generic;
4+
using System.Linq;
35
using System.Threading.Tasks;
46
using Common;
57
using Infrastructure;
@@ -49,5 +51,22 @@ public Task ShouldReuseACachedProjectionMapper()
4951
mapper.RootMapperCountShouldBeOne();
5052
});
5153
}
54+
55+
[Fact]
56+
public Task ShouldMapAQueryableAsAnEnumerable()
57+
{
58+
return RunTest(async (context, mapper) =>
59+
{
60+
await context.BoolItems.AddRangeAsync(new PublicBool { Value = true }, new PublicBool { Value = false });
61+
await context.SaveChangesAsync();
62+
63+
var result = mapper
64+
.Map(context.BoolItems.Where(bi => bi.Value))
65+
.ToANew<List<PublicBoolDto>>();
66+
67+
result.ShouldNotBeNull();
68+
result.ShouldHaveSingleItem().Value.ShouldBeTrue();
69+
});
70+
}
5271
}
5372
}

AgileMapper.UnitTests/AgileMapper.UnitTests.csproj

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@
4444
<Reference Include="AgileObjects.NetStandardPolyfills, Version=1.4.0.0, Culture=neutral, PublicKeyToken=06131ac1c008ad4e, processorArchitecture=MSIL">
4545
<HintPath>..\packages\AgileObjects.NetStandardPolyfills.1.4.0\lib\net40\AgileObjects.NetStandardPolyfills.dll</HintPath>
4646
</Reference>
47-
<Reference Include="AgileObjects.ReadableExpressions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=9f54ad81db69da8e, processorArchitecture=MSIL">
48-
<HintPath>..\packages\AgileObjects.ReadableExpressions.2.1.1\lib\net40\AgileObjects.ReadableExpressions.dll</HintPath>
47+
<Reference Include="AgileObjects.ReadableExpressions, Version=2.3.2.0, Culture=neutral, PublicKeyToken=9f54ad81db69da8e, processorArchitecture=MSIL">
48+
<HintPath>..\packages\AgileObjects.ReadableExpressions.2.3.2\lib\net40\AgileObjects.ReadableExpressions.dll</HintPath>
4949
</Reference>
5050
<Reference Include="Microsoft.Extensions.Primitives, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
5151
<HintPath>..\packages\Microsoft.Extensions.Primitives.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
@@ -103,6 +103,9 @@
103103
<Compile Include="Configuration\Inline\WhenConfiguringTypeIdentifiersInline.cs" />
104104
<Compile Include="Configuration\Inline\WhenIgnoringMembersInline.cs" />
105105
<Compile Include="Configuration\Inline\WhenIgnoringMembersInlineIncorrectly.cs" />
106+
<Compile Include="Configuration\Inline\WhenIgnoringSourceMemberInlineIncorrectly.cs" />
107+
<Compile Include="Configuration\Inline\WhenIgnoringSourceMembersByValueFilterInline.cs" />
108+
<Compile Include="Configuration\Inline\WhenIgnoringSourceMembersInline.cs" />
106109
<Compile Include="Configuration\Inline\WhenMappingToNullInline.cs" />
107110
<Compile Include="Configuration\Inline\WhenValidatingMappingsInline.cs" />
108111
<Compile Include="Configuration\Inline\WhenViewingMappingPlans.cs" />
@@ -111,6 +114,12 @@
111114
<Compile Include="Configuration\WhenConfiguringEntityMapping.cs" />
112115
<Compile Include="Configuration\WhenConfiguringReverseDataSources.cs" />
113116
<Compile Include="Configuration\WhenConfiguringReverseDataSourcesIncorrectly.cs" />
117+
<Compile Include="Configuration\WhenIgnoringSourceMembers.cs" />
118+
<Compile Include="Configuration\WhenIgnoringSourceMembersByFilter.cs" />
119+
<Compile Include="Configuration\WhenIgnoringSourceMembersByGlobalFilter.cs" />
120+
<Compile Include="Configuration\WhenIgnoringSourceMembersByValueFilter.cs" />
121+
<Compile Include="Configuration\WhenIgnoringSourceMembersByValueFilterIncorrectly.cs" />
122+
<Compile Include="Configuration\WhenIgnoringSourceMembersIncorrectly.cs" />
114123
<Compile Include="Configuration\WhenResolvingServices.cs" />
115124
<Compile Include="Configuration\WhenViewingMappingPlans.cs" />
116125
<Compile Include="Dictionaries\WhenMappingFromDictionariesOnToComplexTypes.cs" />
@@ -144,6 +153,7 @@
144153
<Compile Include="Extensions\WhenUnflatteningFromQueryStringsViaExtensionMethods.cs" />
145154
<Compile Include="Extensions\WhenUnflatteningViaExtensionMethods.cs" />
146155
<Compile Include="MapperCloning\WhenCloningConstructorDataSources.cs" />
156+
<Compile Include="MapperCloning\WhenCloningDictionarySettings.cs" />
147157
<Compile Include="MapperCloning\WhenCloningMemberIgnores.cs" />
148158
<Compile Include="Configuration\WhenConfiguringObjectTracking.cs" />
149159
<Compile Include="Configuration\WhenConfiguringObjectTrackingIncorrectly.cs" />
@@ -219,7 +229,9 @@
219229
<Compile Include="TestClasses\PaymentTypeUk.cs" />
220230
<Compile Include="TestClasses\PaymentTypeUs.cs" />
221231
<Compile Include="TestClasses\PublicCtorStruct.cs" />
232+
<Compile Include="TestClasses\PublicEnumerable.cs" />
222233
<Compile Include="TestClasses\PublicImplementation.cs" />
234+
<Compile Include="TestClasses\PublicIndex.cs" />
223235
<Compile Include="TestClasses\PublicSealed.cs" />
224236
<Compile Include="TestClasses\PublicPropertyStruct.cs" />
225237
<Compile Include="TestClasses\PublicTwoFields.cs" />
@@ -301,6 +313,7 @@
301313
<Compile Include="WhenMappingToNewEnumerableMembers.cs" />
302314
<Compile Include="WhenMappingToNewEnumerables.cs" />
303315
<Compile Include="Members\WhenMatchingSourceToTargetMembers.cs" />
316+
<Compile Include="WhenWorkingWithQueryStrings.cs" />
304317
</ItemGroup>
305318
<ItemGroup>
306319
<None Include="app.config">

AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringDataSourcesInline.cs

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
using Common;
88
using TestClasses;
99
#if !NET35
10+
using NetStandardPolyfills;
1011
using Xunit;
12+
using static System.Linq.Expressions.Expression;
1113
#else
1214
using Fact = NUnit.Framework.TestAttribute;
1315

@@ -317,6 +319,194 @@ public void ShouldApplyDifferingTargetTypeInlineDataSourceMemberConfig()
317319
}
318320
}
319321

322+
[Fact]
323+
public void ShouldApplyAnInlineNullCheckedArrayIndexDataSource()
324+
{
325+
using (var mapper = Mapper.CreateNew())
326+
{
327+
var source = new PublicProperty<PublicField<Address>[]>
328+
{
329+
Value = new[]
330+
{
331+
new PublicField<Address> { Value = new Address { Line1 = "1.1" } },
332+
new PublicField<Address> { Value = new Address { Line1 = "1.2" } }
333+
}
334+
};
335+
336+
var result = mapper.Map(source).ToANew<PublicProperty<Address>>(cfg => cfg
337+
.Map(s => s.Value[1].Value, t => t.Value));
338+
339+
result.Value.ShouldNotBeNull();
340+
result.Value.Line1.ShouldBe("1.2");
341+
342+
var nullArraySource = new PublicProperty<PublicField<Address>[]> { Value = null };
343+
344+
var nullArrayResult = mapper.Map(nullArraySource).ToANew<PublicProperty<Address>>(cfg => cfg
345+
.Map(s => s.Value[1].Value, t => t.Value));
346+
347+
nullArrayResult.Value.ShouldBeNull();
348+
349+
var tooSmallArraySource = new PublicProperty<PublicField<Address>[]>
350+
{
351+
Value = new[]
352+
{
353+
new PublicField<Address> { Value = new Address { Line1 = "1.1" } }
354+
}
355+
};
356+
357+
var tooSmallArrayResult = mapper.Map(tooSmallArraySource).ToANew<PublicProperty<Address>>(cfg => cfg
358+
.Map(s => s.Value[1].Value, t => t.Value));
359+
360+
tooSmallArrayResult.Value.ShouldBeNull();
361+
362+
var nullArrayObjectSource = new PublicProperty<PublicField<Address>[]>
363+
{
364+
Value = new[]
365+
{
366+
new PublicField<Address> { Value = new Address { Line1 = "1.1" } },
367+
new PublicField<Address> { Value = null }
368+
}
369+
};
370+
371+
var nullArrayObjectResult = mapper.Map(nullArrayObjectSource).ToANew<PublicProperty<Address>>(cfg => cfg
372+
.Map(s => s.Value[1].Value, t => t.Value));
373+
374+
nullArrayObjectResult.Value.ShouldBeNull();
375+
}
376+
}
377+
378+
#if !NET35
379+
// System.Linq.Expressions.Expression.MakeIndex() is missing in .NET 3.5, so not much danger of this configuration:
380+
[Fact]
381+
public void ShouldApplyAnInlineNullCheckedIntKeyedIndexDataSource()
382+
{
383+
using (var mapper = Mapper.CreateNew())
384+
{
385+
var source = new PublicProperty<PublicIndex<int, PublicField<Address>>>
386+
{
387+
Value = new PublicIndex<int, PublicField<Address>>
388+
{
389+
[0] = new PublicField<Address> { Value = new Address { Line1 = "1.1" } },
390+
[1] = new PublicField<Address> { Value = new Address { Line1 = "1.2" } }
391+
}
392+
};
393+
394+
var sourceParameter = Parameter(source.GetType(), "s");
395+
var sourceValueProperty = Property(sourceParameter, "Value");
396+
var sourceValueIndexer = sourceValueProperty.Type.GetPublicInstanceProperty("Item");
397+
var sourceValueIndex = MakeIndex(sourceValueProperty, sourceValueIndexer, new[] { Constant(1) });
398+
399+
var sourceLambda = Lambda<Func<PublicProperty<PublicIndex<int, PublicField<Address>>>, Address>>(
400+
Field(sourceValueIndex, "Value"),
401+
sourceParameter);
402+
403+
var result = mapper.Map(source).ToANew<PublicField<Address>>(cfg => cfg
404+
.Map(sourceLambda, t => t.Value));
405+
406+
result.Value.ShouldNotBeNull();
407+
result.Value.Line1.ShouldBe("1.2");
408+
409+
var nullIndexerSource = new PublicProperty<PublicIndex<int, PublicField<Address>>> { Value = null };
410+
411+
var nullIndexerResult = mapper.Map(nullIndexerSource).ToANew<PublicProperty<Address>>(cfg => cfg
412+
.Map(sourceLambda, t => t.Value));
413+
414+
nullIndexerResult.Value.ShouldBeNull();
415+
416+
var noEntrySource = new PublicProperty<PublicIndex<int, PublicField<Address>>>
417+
{
418+
Value = new PublicIndex<int, PublicField<Address>>
419+
{
420+
[0] = new PublicField<Address> { Value = new Address { Line1 = "1.1" } }
421+
}
422+
};
423+
424+
var noEntryResult = mapper.Map(noEntrySource).ToANew<PublicProperty<Address>>(cfg => cfg
425+
.Map(sourceLambda, t => t.Value));
426+
427+
noEntryResult.Value.ShouldBeNull();
428+
429+
var nullIndexedObjectSource = new PublicProperty<PublicIndex<int, PublicField<Address>>>
430+
{
431+
Value = new PublicIndex<int, PublicField<Address>>
432+
{
433+
[0] = new PublicField<Address> { Value = new Address { Line1 = "1.1" } },
434+
[1] = new PublicField<Address> { Value = null }
435+
}
436+
};
437+
438+
var nullIndexedObjectResult = mapper.Map(nullIndexedObjectSource).ToANew<PublicProperty<Address>>(cfg => cfg
439+
.Map(sourceLambda, t => t.Value));
440+
441+
nullIndexedObjectResult.Value.ShouldBeNull();
442+
}
443+
}
444+
445+
[Fact]
446+
public void ShouldApplyAnInlineNullCheckedStringKeyedIndexDataSource()
447+
{
448+
using (var mapper = Mapper.CreateNew())
449+
{
450+
var source = new PublicProperty<PublicIndex<string, PublicField<Address>>>
451+
{
452+
Value = new PublicIndex<string, PublicField<Address>>
453+
{
454+
["A"] = new PublicField<Address> { Value = new Address { Line1 = "1.1" } },
455+
["B"] = new PublicField<Address> { Value = new Address { Line1 = "1.2" } }
456+
}
457+
};
458+
459+
var sourceParameter = Parameter(source.GetType(), "s");
460+
var sourceValueProperty = Property(sourceParameter, "Value");
461+
var sourceValueIndexer = sourceValueProperty.Type.GetPublicInstanceProperty("Item");
462+
var sourceValueIndex = MakeIndex(sourceValueProperty, sourceValueIndexer, new[] { Constant("B") });
463+
464+
var sourceLambda = Lambda<Func<PublicProperty<PublicIndex<string, PublicField<Address>>>, Address>>(
465+
Field(sourceValueIndex, "Value"),
466+
sourceParameter);
467+
468+
var result = mapper.Map(source).ToANew<PublicField<Address>>(cfg => cfg
469+
.Map(sourceLambda, t => t.Value));
470+
471+
result.Value.ShouldNotBeNull();
472+
result.Value.Line1.ShouldBe("1.2");
473+
474+
var nullIndexerSource = new PublicProperty<PublicIndex<string, PublicField<Address>>> { Value = null };
475+
476+
var nullIndexerResult = mapper.Map(nullIndexerSource).ToANew<PublicProperty<Address>>(cfg => cfg
477+
.Map(sourceLambda, t => t.Value));
478+
479+
nullIndexerResult.Value.ShouldBeNull();
480+
481+
var noEntrySource = new PublicProperty<PublicIndex<string, PublicField<Address>>>
482+
{
483+
Value = new PublicIndex<string, PublicField<Address>>
484+
{
485+
["A"] = new PublicField<Address> { Value = new Address { Line1 = "1.1" } }
486+
}
487+
};
488+
489+
var noEntryResult = mapper.Map(noEntrySource).ToANew<PublicProperty<Address>>(cfg => cfg
490+
.Map(sourceLambda, t => t.Value));
491+
492+
noEntryResult.Value.ShouldBeNull();
493+
494+
var nullIndexedObjectSource = new PublicProperty<PublicIndex<string, PublicField<Address>>>
495+
{
496+
Value = new PublicIndex<string, PublicField<Address>>
497+
{
498+
["A"] = new PublicField<Address> { Value = new Address { Line1 = "1.1" } },
499+
["B"] = new PublicField<Address> { Value = null }
500+
}
501+
};
502+
503+
var nullIndexedObjectResult = mapper.Map(nullIndexedObjectSource).ToANew<PublicProperty<Address>>(cfg => cfg
504+
.Map(sourceLambda, t => t.Value));
505+
506+
nullIndexedObjectResult.Value.ShouldBeNull();
507+
}
508+
}
509+
#endif
320510
[Fact]
321511
public void ShouldHandleANullSourceMember()
322512
{

0 commit comments

Comments
 (0)