diff --git a/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj b/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj
index a553d6056..d3aaa8cff 100644
--- a/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj
+++ b/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj
@@ -90,6 +90,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -125,10 +137,13 @@
+
+
+
@@ -214,6 +229,7 @@
AgileMapper.UnitTests.MoreTestClasses
+
diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringMappingCallbacks.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringMappingCallbacks.cs
index dac3a5dcc..415cb38ce 100644
--- a/AgileMapper.UnitTests/Configuration/WhenConfiguringMappingCallbacks.cs
+++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringMappingCallbacks.cs
@@ -15,9 +15,7 @@ public void ShouldExecuteAGlobalPreMappingCallback()
{
var mappedNames = new List();
- mapper
- .Before
- .MappingBegins
+ mapper.Before.MappingBegins
.Call((s, t) => mappedNames.AddRange(new[] { ((Person)s).Name, ((PersonViewModel)t).Name }));
var source = new Person { Name = "Bernie" };
@@ -36,9 +34,7 @@ public void ShouldExecuteAGlobalPostMappingCallbackConditionally()
{
var mappedNames = new List();
- 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 }));
diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectCreationCallbacks.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectCreationCallbacks.cs
index 0f6f6fae8..d92993430 100644
--- a/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectCreationCallbacks.cs
+++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectCreationCallbacks.cs
@@ -18,59 +18,62 @@ public void ShouldCallAGlobalObjectCreatedCallback()
{
using (var mapper = Mapper.CreateNew())
{
- var createdInstance = default(PublicProperty);
+ var createdInstance = default(object);
mapper.After
.CreatingInstances
- .Call(ctx => createdInstance = (PublicProperty)ctx.CreatedObject);
+ .Call(ctx => createdInstance = ctx.CreatedObject);
var source = new PublicField();
var result = mapper.Map(source).ToANew>();
createdInstance.ShouldNotBeNull();
- createdInstance.ShouldBe(result);
+ createdInstance.ShouldBeOfType>();
+ createdInstance.ShouldBeSameAs(result);
}
}
[Fact]
public void ShouldWrapAnObjectCreatedCallbackException()
{
- Should.Throw(() =>
+ var createdEx = Should.Throw(() =>
{
using (var mapper = Mapper.CreateNew())
{
mapper.After
.CreatingInstances
- .Call(ctx => { throw new InvalidOperationException(); });
+ .Call(ctx => throw new InvalidOperationException());
mapper.Map(new PublicProperty()).ToANew>();
}
});
+
+ createdEx.ShouldNotBeNull();
+ createdEx.Message.ShouldContain("mapping PublicProperty -> PublicField");
}
[Fact]
public void ShouldWrapANestedObjectCreatingCallbackException()
{
- var exception = Should.Throw(() =>
+ var createdEx = Should.Throw(() =>
{
using (var mapper = Mapper.CreateNew())
{
- mapper
- .After
+ mapper.After
.CreatingInstancesOf()
- .Call(ctx => { throw new InvalidOperationException("OH NO"); });
+ .Call(ctx => throw new InvalidOperationException("OH NO"));
mapper.Map(new PersonViewModel { AddressLine1 = "My House" }).ToANew();
}
});
- exception.InnerException.ShouldNotBeNull();
- exception.InnerException.ShouldBeOfType();
+ createdEx.InnerException.ShouldNotBeNull();
+ createdEx.InnerException.ShouldBeOfType();
// ReSharper disable once PossibleNullReferenceException
- exception.InnerException.InnerException.ShouldNotBeNull();
- exception.InnerException.InnerException.ShouldBeOfType();
+ createdEx.InnerException.InnerException.ShouldNotBeNull();
+ createdEx.InnerException.InnerException.ShouldBeOfType();
// ReSharper disable once PossibleNullReferenceException
- exception.InnerException.InnerException.Message.ShouldBe("OH NO");
+ createdEx.InnerException.InnerException.Message.ShouldBe("OH NO");
}
[Fact]
diff --git a/AgileMapper.UnitTests/Configuration/WhenIgnoringMembersIncorrectly.cs b/AgileMapper.UnitTests/Configuration/WhenIgnoringMembersIncorrectly.cs
index a2f2fe34e..39e3a9ec1 100644
--- a/AgileMapper.UnitTests/Configuration/WhenIgnoringMembersIncorrectly.cs
+++ b/AgileMapper.UnitTests/Configuration/WhenIgnoringMembersIncorrectly.cs
@@ -149,7 +149,7 @@ public void ShouldErrorIfReadOnlySimpleTypeMemberSpecified()
}
});
- configurationEx.Message.ShouldContain("not writeable");
+ configurationEx.Message.ShouldContain("not mappable");
}
[Fact]
diff --git a/AgileMapper.UnitTests/Members/WhenFindingTargetMembers.cs b/AgileMapper.UnitTests/Members/WhenFindingTargetMembers.cs
index 1a5a09466..79d7c0336 100644
--- a/AgileMapper.UnitTests/Members/WhenFindingTargetMembers.cs
+++ b/AgileMapper.UnitTests/Members/WhenFindingTargetMembers.cs
@@ -70,41 +70,49 @@ public void ShouldFindAPublicReadOnlyComplexTypeProperty()
}
[Fact]
- public void ShouldIgnoreANonPublicField()
+ public void ShouldFindAPublicReadOnlyArrayField()
{
var member = MemberFinder
- .GetTargetMembers(typeof(InternalField>))
+ .GetTargetMembers(typeof(PublicReadOnlyField))
.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))
+ .GetTargetMembers(typeof(PublicReadOnlyProperty))
.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))
- .FirstOrDefault(m => m.Name == "Value");
+ .GetTargetMembers(typeof(PublicReadOnlyProperty))
+ .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))
- .FirstOrDefault(m => m.Name.StartsWith("Value"));
+ .GetTargetMembers(typeof(InternalField>))
+ .FirstOrDefault(m => m.Name == "Value");
member.ShouldBeNull();
}
diff --git a/AgileMapper.UnitTests/Reflection/WhenAccessingTypeInformation.cs b/AgileMapper.UnitTests/Reflection/WhenAccessingTypeInformation.cs
index 034bdba09..0b25c2a51 100644
--- a/AgileMapper.UnitTests/Reflection/WhenAccessingTypeInformation.cs
+++ b/AgileMapper.UnitTests/Reflection/WhenAccessingTypeInformation.cs
@@ -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()
{
diff --git a/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructCreationCallbacks.cs b/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructCreationCallbacks.cs
new file mode 100644
index 000000000..5e627387a
--- /dev/null
+++ b/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructCreationCallbacks.cs
@@ -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 { Value = 123456 };
+ var result = mapper.Map(source).ToANew>();
+
+ createdInstance.ShouldNotBeNull();
+ createdInstance.ShouldBeOfType>();
+ result.Value.ShouldBe(123456);
+ }
+ }
+
+ [Fact]
+ public void ShouldCallAnObjectCreatedCallbackForASpecifiedStructType()
+ {
+ using (var mapper = Mapper.CreateNew())
+ {
+ var createdStruct = default(PublicPropertyStruct);
+
+ mapper.After
+ .CreatingInstancesOf>()
+ .Call((s, t, p) => createdStruct = p);
+
+ var source = new { Value = "12345" };
+ var nonMatchingResult = mapper.Map(source).ToANew>();
+
+ createdStruct.ShouldBeDefault();
+ nonMatchingResult.Value.ShouldBe(12345);
+
+ var matchingResult = mapper.Map(source).ToANew>();
+
+ createdStruct.ShouldNotBeNull();
+ createdStruct.ShouldBe(matchingResult);
+ }
+ }
+
+ [Fact]
+ public void ShouldCallAnObjectCreatedCallbackForSpecifiedSourceStructType()
+ {
+ using (var mapper = Mapper.CreateNew())
+ {
+ var creationCount = 0;
+
+ mapper.WhenMapping
+ .From>()
+ .To()
+ .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();
+
+ creationCount.ShouldBe(0);
+ nonMatchingResult.Name.ShouldBe("Goldblum");
+
+ var matchingSource = new PublicPropertyStruct { Value = "Fishy" };
+ var matchingResult = mapper.Map(matchingSource).ToANew();
+
+ creationCount.ShouldBe(1);
+ matchingResult.Name.ShouldBe("Fishy");
+ }
+ }
+
+ [Fact]
+ public void ShouldCallAnObjectCreatedCallbackForSpecifiedSourceAndTargetStructTypes()
+ {
+ using (var mapper = Mapper.CreateNew())
+ {
+ var createdStruct = default(PublicCtorStruct);
+
+ mapper.WhenMapping
+ .From>()
+ .To>()
+ .After
+ .CreatingTargetInstances
+ .Call(ctx => createdStruct = ctx.CreatedObject);
+
+ var nonMatchingSource = new { Value = "8765" };
+ var nonMatchingResult = mapper.Map(nonMatchingSource).ToANew>();
+
+ createdStruct.ShouldBeDefault();
+ nonMatchingResult.Value.ShouldBe(8765);
+
+ var matchingSource = new PublicPropertyStruct { Value = 5678 };
+ var matchingResult = mapper.Map(matchingSource).ToANew>();
+
+ createdStruct.ShouldNotBeNull();
+ createdStruct.ShouldBe(matchingResult);
+ }
+ }
+ }
+}
diff --git a/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructDataSources.cs b/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructDataSources.cs
new file mode 100644
index 000000000..a55acb152
--- /dev/null
+++ b/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructDataSources.cs
@@ -0,0 +1,114 @@
+namespace AgileObjects.AgileMapper.UnitTests.Structs.Configuration
+{
+ using System;
+ using AgileMapper.Extensions;
+ using TestClasses;
+ using Xunit;
+
+ public class WhenConfiguringStructDataSources
+ {
+ [Fact]
+ public void ShouldApplyAConfiguredConstantByConstructorParameterType()
+ {
+ using (var mapper = Mapper.CreateNew())
+ {
+ mapper.WhenMapping
+ .From>()
+ .To>()
+ .Map("Not a Guid")
+ .ToCtor();
+
+ var source = new PublicProperty { Value = Guid.NewGuid() };
+ var result = mapper.Map(source).ToANew>();
+
+ result.Value.ShouldBe("Not a Guid");
+ }
+ }
+
+ [Fact]
+ public void ShouldApplyAConfiguredExpressionByConstructorParameterType()
+ {
+ using (var mapper = Mapper.CreateNew())
+ {
+ mapper.WhenMapping
+ .From>()
+ .To>()
+ .Map(ctx => ctx.Source.Value.ToString().Length)
+ .ToCtor();
+
+ var guid = Guid.NewGuid();
+ var source = new PublicField { Value = guid };
+ var result = mapper.Map(source).ToANew>();
+
+ result.Value.ShouldBe(guid.ToString().Length);
+ }
+ }
+
+ [Fact]
+ public void ShouldApplyAConfiguredExpressionByConstructorParameterName()
+ {
+ using (var mapper = Mapper.CreateNew())
+ {
+ mapper.WhenMapping
+ .From>()
+ .To>()
+ .Map((s, t, i) => s.Value * i)
+ .ToCtor("value");
+
+ var source = new[]
+ {
+ new PublicPropertyStruct { Value = 11 },
+ new PublicPropertyStruct { Value = 22 },
+ new PublicPropertyStruct { Value = 33 }
+ };
+ var result = mapper.Map(source).ToANew[]>();
+
+ result.Length.ShouldBe(3);
+
+ result.First().Value.ShouldBe(11 * 0);
+ result.Second().Value.ShouldBe(22 * 1);
+ result.Third().Value.ShouldBe(33 * 2);
+ }
+ }
+
+ [Fact]
+ public void ShouldApplyAConfiguredConstant()
+ {
+ using (var mapper = Mapper.CreateNew())
+ {
+ mapper.WhenMapping
+ .From>()
+ .To>()
+ .Map("-- CONFIGURED --")
+ .To(pps => pps.Value);
+
+ var source = new PublicPropertyStruct { Value = "Mapped!" };
+ var result = mapper.Map(source).ToANew>();
+
+ result.Value.ShouldBe("-- CONFIGURED --");
+ }
+ }
+
+ [Fact]
+ public void ShouldApplyAConfiguredMember()
+ {
+ using (var mapper = Mapper.CreateNew())
+ {
+ mapper.WhenMapping
+ .From()
+ .To>()
+ .Map(ctx => ctx.Source.Id)
+ .To(pfs => pfs.Value1)
+ .And
+ .Map(ctx => ctx.Source.Name)
+ .To(pfs => pfs.Value2);
+
+ var source = new MysteryCustomer { Id = Guid.NewGuid(), Name = "Gyles" };
+ var result = mapper.Map(source).ToANew>();
+
+ result.Value1.ShouldBe(source.Id);
+ result.Value2.ShouldBe("Gyles");
+ }
+ }
+ }
+}
diff --git a/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructMappingCallbacks.cs b/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructMappingCallbacks.cs
new file mode 100644
index 000000000..1f7133be2
--- /dev/null
+++ b/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructMappingCallbacks.cs
@@ -0,0 +1,95 @@
+namespace AgileObjects.AgileMapper.UnitTests.Structs.Configuration
+{
+ using System;
+ using System.Collections.Generic;
+ using AgileMapper.Configuration;
+ using AgileMapper.Extensions;
+ using Shouldly;
+ using TestClasses;
+ using Xunit;
+
+ public class WhenConfiguringStructMappingCallbacks
+ {
+ [Fact]
+ public void ShouldExecuteAGlobalPreMappingCallback()
+ {
+ using (var mapper = Mapper.CreateNew())
+ {
+ var mappedTypes = new List();
+
+ mapper.Before.MappingBegins
+ .Call((s, t) => mappedTypes.Add(t.GetType()));
+
+ mapper.Map(new { Value = "Bernie" }).OnTo(new PublicTwoFieldsStruct());
+ mapper.Map(new PublicPropertyStruct()).Over(new PublicPropertyStruct());
+
+ mappedTypes.ShouldNotBeEmpty();
+ mappedTypes.ShouldBe(typeof(PublicTwoFieldsStruct), typeof(PublicPropertyStruct));
+ }
+ }
+
+ [Fact]
+ public void ShouldExecuteAGlobalPostMappingCallback()
+ {
+ using (var mapper = Mapper.CreateNew())
+ {
+ var mappedTargets = new List