Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
e638328
Start of support for mapping to structs
SteveWilkes Mar 24, 2017
4320247
Test coverage for struct and interface type evaluation
SteveWilkes Mar 24, 2017
41c416d
Support for mapping to nested user-defined, parameterised structs
SteveWilkes Mar 25, 2017
17005a2
Extra test coverage, re: issue #10
SteveWilkes Mar 27, 2017
f62b141
Re-using existing target complex type objects instead of using a loca…
SteveWilkes Mar 28, 2017
42c81d2
Support for post-creation callbacks in struct mapping
SteveWilkes Apr 2, 2017
4a60490
Tidying
SteveWilkes May 6, 2017
4843e72
Merging from master
SteveWilkes May 7, 2017
26ffb48
Support for specific-type struct-creation callbacks
SteveWilkes May 8, 2017
6cfe9c3
Support for object created callbacks for specified source and target …
SteveWilkes May 8, 2017
4d99d6a
Test coverage for object creation callbacks when mapping from structs…
SteveWilkes May 8, 2017
828bd59
Merge branch 'master' into StructSupport
SteveWilkes May 8, 2017
f2624a8
Merging from branch master
SteveWilkes May 9, 2017
6df37f8
Merge branch 'master' into StructSupport
SteveWilkes May 9, 2017
5f17063
Merging from master branch
SteveWilkes May 13, 2017
1451acc
Merging from master / Using local variables for derived type mapping
SteveWilkes Sep 28, 2017
3739fd3
Organising tests
SteveWilkes Sep 29, 2017
53051e6
Extra test coverage for mapping to new root structs
SteveWilkes Sep 29, 2017
c7d7bc9
Extending test coverage for mapping to new nested structs / Reusing a…
SteveWilkes Sep 29, 2017
ab6577f
Support for runtime-typing constructor arguments / Test coverage for …
SteveWilkes Sep 29, 2017
ed71e19
Adding MapperData.TargetMemberIsUserStruct helper method
SteveWilkes Sep 30, 2017
498c318
Guarding readonly struct member population with a is non-default comp…
SteveWilkes Sep 30, 2017
0faec42
Skipping local variable use when mapping populated, readonly, complex…
SteveWilkes Sep 30, 2017
13b43f4
Skipping fallback data source creation for readonly target member
SteveWilkes Sep 30, 2017
0f90e9b
Constructing structs using member initialisations
SteveWilkes Oct 6, 2017
0e1646d
Simplifying construction of struct mapping member binding expressions
SteveWilkes Oct 9, 2017
4ed7f0d
Simplifying target object use when mapping to an enumerable in a writ…
SteveWilkes Oct 9, 2017
2f5c563
Ignoring non-simple members when mapping structs - expression compile…
SteveWilkes Oct 9, 2017
1ad8845
Test coverage for complex type struct members
SteveWilkes Oct 9, 2017
210c750
Adding TODO
SteveWilkes Oct 9, 2017
302c200
Support for 'overwriting' a root struct
SteveWilkes Oct 9, 2017
2c411cd
Test coverage for mapping over struct members with default values
SteveWilkes Oct 9, 2017
6775e7e
Test coverage for struct overwrite mapping with a null source
SteveWilkes Oct 9, 2017
8f00631
Test coverage for overwriting a struct member to the default value
SteveWilkes Oct 9, 2017
6d30a9c
Converting configured constant values at configuration time instead o…
SteveWilkes Oct 9, 2017
9b3507f
Test coverage for mapping over a struct with a source without all mat…
SteveWilkes Oct 9, 2017
1154708
Test coverage for configuring a custom source value expression for a …
SteveWilkes Oct 9, 2017
aecf43a
Removing unused code
SteveWilkes Oct 9, 2017
965b430
Moving binding - population decision into MemberPopulation
SteveWilkes Oct 10, 2017
fec65aa
Start of support for struct merging
SteveWilkes Oct 10, 2017
27dce03
Extra test coverage for struct merging
SteveWilkes Oct 10, 2017
f1b8122
Support for merge mapping nested struct members
SteveWilkes Oct 10, 2017
5462821
Erroring if member population callbacks are configured for structs
SteveWilkes Oct 10, 2017
566957c
Support for passing target structs to a configured global pre-mapping…
SteveWilkes Oct 10, 2017
ac573a6
Test coverage for configured global post-struct-mapping callback
SteveWilkes Oct 10, 2017
e80cee1
Skipping module 1 == 0 check on numeric conversions from nullable types
SteveWilkes Oct 12, 2017
f94b0db
Test coverage for struct constructor parameter data source configurat…
SteveWilkes Oct 12, 2017
bf92c3f
Test coverage for configuring data sources for struct members
SteveWilkes Oct 12, 2017
f7da691
Test coverage for mapping from dictionaries to structs + enumerables …
SteveWilkes Oct 12, 2017
d5aded3
Test coverage for struct enumerable mapping / Fixing overwrite mappin…
SteveWilkes Oct 12, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions AgileMapper.UnitTests/AgileMapper.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,18 @@
<Compile Include="Dictionaries\WhenCreatingRootDictionaryMembers.cs" />
<Compile Include="MapperCloning\WhenCloningMapperObjectFactories.cs" />
<Compile Include="SimpleTypeConversion\WhenConvertingToCharacters.cs" />
<Compile Include="Structs\Configuration\WhenConfiguringStructCreationCallbacks.cs" />
<Compile Include="Structs\Configuration\WhenConfiguringStructDataSources.cs" />
<Compile Include="Structs\Configuration\WhenConfiguringStructMappingCallbacks.cs" />
<Compile Include="Structs\Dictionaries\WhenMappingFromDictionariesToStructs.cs" />
<Compile Include="Structs\WhenMappingOnToStructMembers.cs" />
<Compile Include="Structs\WhenMappingOnToStructs.cs" />
<Compile Include="Structs\WhenMappingOverStructMembers.cs" />
<Compile Include="Structs\WhenMappingOverStructs.cs" />
<Compile Include="Structs\WhenMappingToStructEnumerables.cs" />
<Compile Include="Structs\WhenMappingToUnmappableStructMembers.cs" />
<Compile Include="Structs\WhenMappingToNewStructMembers.cs" />
<Compile Include="Structs\WhenMappingToNewStructs.cs" />
<Compile Include="TestClasses\Earthworm.cs" />
<Compile Include="TestClasses\IPublicInterface.cs" />
<Compile Include="TestClasses\MegaProduct.cs" />
Expand Down Expand Up @@ -125,10 +137,13 @@
<Compile Include="TestClasses\OrderUs.cs" />
<Compile Include="TestClasses\PaymentTypeUk.cs" />
<Compile Include="TestClasses\PaymentTypeUs.cs" />
<Compile Include="TestClasses\PublicCtorStruct.cs" />
<Compile Include="TestClasses\PublicFactoryMethod.cs" />
<Compile Include="TestClasses\PublicImplementation.cs" />
<Compile Include="TestClasses\PublicSealed.cs" />
<Compile Include="TestClasses\PublicPropertyStruct.cs" />
<Compile Include="TestClasses\PublicTwoFields.cs" />
<Compile Include="TestClasses\PublicTwoFieldsStruct.cs" />
<Compile Include="TestClasses\PublicTwoParamCtor.cs" />
<Compile Include="TestClasses\Wedding.cs" />
<Compile Include="TestClasses\WeddingDto.cs" />
Expand Down Expand Up @@ -214,6 +229,7 @@
<Name>AgileMapper.UnitTests.MoreTestClasses</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ public void ShouldExecuteAGlobalPreMappingCallback()
{
var mappedNames = new List<string>();

mapper
.Before
.MappingBegins
mapper.Before.MappingBegins
.Call((s, t) => mappedNames.AddRange(new[] { ((Person)s).Name, ((PersonViewModel)t).Name }));

var source = new Person { Name = "Bernie" };
Expand All @@ -36,9 +34,7 @@ public void ShouldExecuteAGlobalPostMappingCallbackConditionally()
{
var mappedNames = new List<string>();

mapper
.After
.MappingEnds
mapper.After.MappingEnds
.If((s, t) => t.GetType() != typeof(Address))
.Call(ctx => mappedNames.AddRange(new[] { ((PersonViewModel)ctx.Source).Name, ((Person)ctx.Target).Name }));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,59 +18,62 @@ public void ShouldCallAGlobalObjectCreatedCallback()
{
using (var mapper = Mapper.CreateNew())
{
var createdInstance = default(PublicProperty<int>);
var createdInstance = default(object);

mapper.After
.CreatingInstances
.Call(ctx => createdInstance = (PublicProperty<int>)ctx.CreatedObject);
.Call(ctx => createdInstance = ctx.CreatedObject);

var source = new PublicField<int>();
var result = mapper.Map(source).ToANew<PublicProperty<int>>();

createdInstance.ShouldNotBeNull();
createdInstance.ShouldBe(result);
createdInstance.ShouldBeOfType<PublicProperty<int>>();
createdInstance.ShouldBeSameAs(result);
}
}

[Fact]
public void ShouldWrapAnObjectCreatedCallbackException()
{
Should.Throw<MappingException>(() =>
var createdEx = Should.Throw<MappingException>(() =>
{
using (var mapper = Mapper.CreateNew())
{
mapper.After
.CreatingInstances
.Call(ctx => { throw new InvalidOperationException(); });
.Call(ctx => throw new InvalidOperationException());

mapper.Map(new PublicProperty<int>()).ToANew<PublicField<int>>();
}
});

createdEx.ShouldNotBeNull();
createdEx.Message.ShouldContain("mapping PublicProperty<int> -> PublicField<int>");
}

[Fact]
public void ShouldWrapANestedObjectCreatingCallbackException()
{
var exception = Should.Throw<MappingException>(() =>
var createdEx = Should.Throw<MappingException>(() =>
{
using (var mapper = Mapper.CreateNew())
{
mapper
.After
mapper.After
.CreatingInstancesOf<Address>()
.Call(ctx => { throw new InvalidOperationException("OH NO"); });
.Call(ctx => throw new InvalidOperationException("OH NO"));

mapper.Map(new PersonViewModel { AddressLine1 = "My House" }).ToANew<Person>();
}
});

exception.InnerException.ShouldNotBeNull();
exception.InnerException.ShouldBeOfType<MappingException>();
createdEx.InnerException.ShouldNotBeNull();
createdEx.InnerException.ShouldBeOfType<MappingException>();
// ReSharper disable once PossibleNullReferenceException
exception.InnerException.InnerException.ShouldNotBeNull();
exception.InnerException.InnerException.ShouldBeOfType<InvalidOperationException>();
createdEx.InnerException.InnerException.ShouldNotBeNull();
createdEx.InnerException.InnerException.ShouldBeOfType<InvalidOperationException>();
// ReSharper disable once PossibleNullReferenceException
exception.InnerException.InnerException.Message.ShouldBe("OH NO");
createdEx.InnerException.InnerException.Message.ShouldBe("OH NO");
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public void ShouldErrorIfReadOnlySimpleTypeMemberSpecified()
}
});

configurationEx.Message.ShouldContain("not writeable");
configurationEx.Message.ShouldContain("not mappable");
}

[Fact]
Expand Down
34 changes: 21 additions & 13 deletions AgileMapper.UnitTests/Members/WhenFindingTargetMembers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,41 +70,49 @@ public void ShouldFindAPublicReadOnlyComplexTypeProperty()
}

[Fact]
public void ShouldIgnoreANonPublicField()
public void ShouldFindAPublicReadOnlyArrayField()
{
var member = MemberFinder
.GetTargetMembers(typeof(InternalField<List<byte>>))
.GetTargetMembers(typeof(PublicReadOnlyField<byte[]>))
.FirstOrDefault(m => m.Name == "Value");

member.ShouldBeNull();
member.ShouldNotBeNull();
member.Type.ShouldBe(typeof(byte[]));
member.ElementType.ShouldBe(typeof(byte));
member.IsWriteable.ShouldBeFalse();
}

[Fact]
public void ShouldIgnoreAPublicReadOnlyArrayField()
public void ShouldFindAPublicReadOnlySimpleTypeProperty()
{
var member = MemberFinder
.GetTargetMembers(typeof(PublicReadOnlyField<byte[]>))
.GetTargetMembers(typeof(PublicReadOnlyProperty<long>))
.FirstOrDefault(m => m.Name == "Value");

member.ShouldBeNull();
member.ShouldNotBeNull();
member.Type.ShouldBe(typeof(long));
member.IsWriteable.ShouldBeFalse();
}

[Fact]
public void ShouldIgnoreAPublicReadOnlySimpleTypeProperty()
public void ShouldFindAReadOnlyArrayProperty()
{
var member = MemberFinder
.GetTargetMembers(typeof(PublicReadOnlyProperty<long>))
.FirstOrDefault(m => m.Name == "Value");
.GetTargetMembers(typeof(PublicReadOnlyProperty<long[]>))
.FirstOrDefault(m => m.Name.StartsWith("Value"));

member.ShouldBeNull();
member.ShouldNotBeNull();
member.Type.ShouldBe(typeof(long[]));
member.ElementType.ShouldBe(typeof(long));
member.IsWriteable.ShouldBeFalse();
}

[Fact]
public void ShouldIgnoreAReadOnlyArrayProperty()
public void ShouldIgnoreANonPublicField()
{
var member = MemberFinder
.GetTargetMembers(typeof(PublicReadOnlyProperty<long[]>))
.FirstOrDefault(m => m.Name.StartsWith("Value"));
.GetTargetMembers(typeof(InternalField<List<byte>>))
.FirstOrDefault(m => m.Name == "Value");

member.ShouldBeNull();
}
Expand Down
14 changes: 13 additions & 1 deletion AgileMapper.UnitTests/Reflection/WhenAccessingTypeInformation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,23 @@ public void ShouldNotEvaluateAStringAsEnumerable()
#region IsComplex

[Fact]
public void ShouldEvaluateAComplexTypeAsComplex()
public void ShouldEvaluateAClassAsComplex()
{
typeof(Person).IsComplex().ShouldBeTrue();
}

[Fact]
public void ShouldEvaluateAStructAsComplex()
{
typeof(PublicCtorStruct<>).IsComplex().ShouldBeTrue();
}

[Fact]
public void ShouldEvaluateAnInterfaceAsComplex()
{
typeof(IPublicInterface<>).IsComplex().ShouldBeTrue();
}

[Fact]
public void ShouldNotEvaluateAnArrayAsComplex()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
namespace AgileObjects.AgileMapper.UnitTests.Structs.Configuration
{
using Shouldly;
using TestClasses;
using Xunit;

public class WhenConfiguringStructCreationCallbacks
{
[Fact]
public void ShouldCallAGlobalObjectCreatedCallbackWithAStruct()
{
using (var mapper = Mapper.CreateNew())
{
var createdInstance = default(object);

mapper.After
.CreatingInstances
.Call(ctx => createdInstance = ctx.CreatedObject);

var source = new PublicField<long> { Value = 123456 };
var result = mapper.Map(source).ToANew<PublicCtorStruct<int>>();

createdInstance.ShouldNotBeNull();
createdInstance.ShouldBeOfType<PublicCtorStruct<int>>();
result.Value.ShouldBe(123456);
}
}

[Fact]
public void ShouldCallAnObjectCreatedCallbackForASpecifiedStructType()
{
using (var mapper = Mapper.CreateNew())
{
var createdStruct = default(PublicPropertyStruct<int>);

mapper.After
.CreatingInstancesOf<PublicPropertyStruct<int>>()
.Call((s, t, p) => createdStruct = p);

var source = new { Value = "12345" };
var nonMatchingResult = mapper.Map(source).ToANew<PublicField<int>>();

createdStruct.ShouldBeDefault();
nonMatchingResult.Value.ShouldBe(12345);

var matchingResult = mapper.Map(source).ToANew<PublicPropertyStruct<int>>();

createdStruct.ShouldNotBeNull();
createdStruct.ShouldBe(matchingResult);
}
}

[Fact]
public void ShouldCallAnObjectCreatedCallbackForSpecifiedSourceStructType()
{
using (var mapper = Mapper.CreateNew())
{
var creationCount = 0;

mapper.WhenMapping
.From<PublicPropertyStruct<string>>()
.To<Customer>()
.Map(ctx => ctx.Source.Value)
.To(c => c.Name)
.And
.After
.CreatingTargetInstances
.Call(ctx => ++creationCount);

var nonMatchingSource = new { Name = "Goldblum" };
var nonMatchingResult = mapper.Map(nonMatchingSource).ToANew<Customer>();

creationCount.ShouldBe(0);
nonMatchingResult.Name.ShouldBe("Goldblum");

var matchingSource = new PublicPropertyStruct<string> { Value = "Fishy" };
var matchingResult = mapper.Map(matchingSource).ToANew<MysteryCustomer>();

creationCount.ShouldBe(1);
matchingResult.Name.ShouldBe("Fishy");
}
}

[Fact]
public void ShouldCallAnObjectCreatedCallbackForSpecifiedSourceAndTargetStructTypes()
{
using (var mapper = Mapper.CreateNew())
{
var createdStruct = default(PublicCtorStruct<long>);

mapper.WhenMapping
.From<PublicPropertyStruct<int>>()
.To<PublicCtorStruct<long>>()
.After
.CreatingTargetInstances
.Call(ctx => createdStruct = ctx.CreatedObject);

var nonMatchingSource = new { Value = "8765" };
var nonMatchingResult = mapper.Map(nonMatchingSource).ToANew<PublicCtorStruct<long>>();

createdStruct.ShouldBeDefault();
nonMatchingResult.Value.ShouldBe(8765);

var matchingSource = new PublicPropertyStruct<int> { Value = 5678 };
var matchingResult = mapper.Map(matchingSource).ToANew<PublicCtorStruct<long>>();

createdStruct.ShouldNotBeNull();
createdStruct.ShouldBe(matchingResult);
}
}
}
}
Loading