Files
Umbraco-CMS/src/Umbraco.Tests/Models/Mapping/AutoMapper6Tests.cs
2017-07-19 18:23:23 +02:00

199 lines
7.2 KiB
C#

using System;
using AutoMapper;
using NUnit.Framework;
namespace Umbraco.Tests.Models.Mapping
{
[TestFixture]
public class AutoMapper6Tests
{
[Test]
public void Test1()
{
ThingProfile.CtorCount = 0;
Assert.AreEqual(0, ThingProfile.CtorCount);
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile<ThingProfile1>();
});
Assert.AreEqual(1, ThingProfile.CtorCount);
Assert.AreEqual(0, MemberValueResolver.CtorCount);
var mapper = config.CreateMapper();
Assert.AreEqual(1, ThingProfile.CtorCount);
Assert.AreEqual(0, MemberValueResolver.CtorCount);
var thingA = new ThingA { ValueInt = 42, ValueString = "foo" };
var thingB = mapper.Map<ThingA, ThingB>(thingA);
Assert.AreEqual(42, thingB.ValueInt);
Assert.AreEqual("!!foo!!", thingB.ValueString);
mapper.Map<ThingA, ThingB>(thingA);
mapper.Map<ThingA, ThingB>(thingA);
mapper.Map<ThingA, ThingB>(thingA);
Assert.AreEqual(1, ThingProfile.CtorCount); // one single profile
Assert.AreEqual(4, MemberValueResolver.CtorCount); // many resolvers
}
[Test]
public void Test2()
{
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile<ThingProfile2>();
});
var mapper = config.CreateMapper();
Assert.AreEqual(0, ValueResolver.CtorCount);
var thingA = new ThingA { ValueInt = 42, ValueString = "foo" };
var thingB = mapper.Map<ThingA, ThingB>(thingA);
Assert.AreEqual(42, thingB.ValueInt);
Assert.AreEqual("!!foo!!", thingB.ValueString);
mapper.Map<ThingA, ThingB>(thingA);
mapper.Map<ThingA, ThingB>(thingA);
mapper.Map<ThingA, ThingB>(thingA);
Assert.AreEqual(4, ValueResolver.CtorCount); // many resolvers
}
[Test]
public void Test3()
{
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile<ThingProfile3>();
});
var mapper = config.CreateMapper();
var thingA = new ThingA { ValueInt = 42, ValueString = "foo" };
var thingB = mapper.Map<ThingA, ThingB>(thingA);
Assert.AreEqual(42, thingB.ValueInt);
Assert.AreEqual("!!foo!!", thingB.ValueString);
mapper.Map<ThingA, ThingB>(thingA);
mapper.Map<ThingA, ThingB>(thingA);
mapper.Map<ThingA, ThingB>(thingA);
}
// Resolve destination member using a custom value resolver
// void ResolveUsing<TValueResolver>()
// where TValueResolver : IValueResolver<TSource, TDestination, TDestMember>;
// Resolve destination member using a custom value resolver from a source member
// void ResolveUsing<TValueResolver, TSourceMember>(Expression<Func<TSource, TSourceMember>> sourceMember)
// where TValueResolver : IMemberValueResolver<TSource, TDestination, TSourceMember, TMember>;
// void ResolveUsing<TValueResolver, TSourceMember>(string sourceMemberName)
// where TValueResolver : IMemberValueResolver<TSource, TDestination, TSourceMember, TMember>;
// Resolve destination member using a custom value resolver instance
// void ResolveUsing(IValueResolver<TSource, TDestination, TMember> valueResolver);
// void ResolveUsing<TSourceMember>(IMemberValueResolver<TSource, TDestination, TSourceMember, TMember> valueResolver, Expression<Func<TSource, TSourceMember>> sourceMember);
// Resolve destination member using a custom value resolver callback
// void ResolveUsing<TResult>(Func<TSource, TResult> resolver);
// void ResolveUsing<TResult>(Func<TSource, TDestination, TResult> resolver);
// void ResolveUsing<TResult>(Func<TSource, TDestination, TMember, TResult> resolver);
// void ResolveUsing<TResult>(Func<TSource, TDestination, TMember, ResolutionContext, TResult> resolver);
// read https://stackoverflow.com/questions/14875075/automapper-what-is-the-difference-between-mapfrom-and-resolveusing
// about the diff between MapFrom and ResolveUsing... keeping ResolveUsing in our code
public class ThingProfile : Profile
{
public static int CtorCount { get; set; }
public ThingProfile(int ver)
{
CtorCount++;
var map = CreateMap<ThingA, ThingB>()
.ForMember(dest => dest.ValueInt, opt => opt.MapFrom(src => src.ValueInt));
switch (ver)
{
case 0:
break;
case 1:
map
.ForMember(dest => dest.ValueString, opt => opt.ResolveUsing<MemberValueResolver, string>(src => src.ValueString));
break;
case 2:
map
.ForMember(dest => dest.ValueString, opt => opt.ResolveUsing<ValueResolver>());
break;
case 3:
// in most cases that should be perfectly enough?
map
.ForMember(dest => dest.ValueString, opt => opt.ResolveUsing(source => "!!" + source.ValueString + "!!"));
break;
default:
throw new ArgumentOutOfRangeException(nameof(ver));
}
}
}
public class ThingProfile1 : ThingProfile
{
public ThingProfile1() : base(1) { }
}
public class ThingProfile2 : ThingProfile
{
public ThingProfile2() : base(2) { }
}
public class ThingProfile3 : ThingProfile
{
public ThingProfile3() : base(3) { }
}
public class ValueResolver : IValueResolver<ThingA, ThingB, string>
{
public static int CtorCount { get; set; }
public ValueResolver()
{
CtorCount++;
}
public string Resolve(ThingA source, ThingB destination, string destMember, ResolutionContext context)
{
return "!!" + source.ValueString + "!!";
}
}
public class MemberValueResolver : IMemberValueResolver<ThingA, ThingB, string, string>
{
public static int CtorCount { get; set; }
public MemberValueResolver()
{
CtorCount++;
}
public string Resolve(ThingA source, ThingB destination, string sourceMember, string destMember, ResolutionContext context)
{
return "!!" + sourceMember + "!!";
}
}
public class ThingA
{
public int ValueInt { get; set; }
public string ValueString { get; set; }
}
public class ThingB
{
public int ValueInt { get; set; }
public string ValueString { get; set; }
}
}
}