From 0f15dc3f29ef33a9f6de5015f791a2d6271307fb Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Fri, 16 Feb 2018 21:26:57 +0100 Subject: [PATCH] Mapper improved to get rid of exceptions. --- .../Reflection/SimpleMapper.cs | 37 +++-- .../Reflection/SimpleMapperTests.cs | 153 ++++++++++++------ 2 files changed, 127 insertions(+), 63 deletions(-) diff --git a/src/Squidex.Infrastructure/Reflection/SimpleMapper.cs b/src/Squidex.Infrastructure/Reflection/SimpleMapper.cs index cc6d8ecd2..0845e39d4 100644 --- a/src/Squidex.Infrastructure/Reflection/SimpleMapper.cs +++ b/src/Squidex.Infrastructure/Reflection/SimpleMapper.cs @@ -16,6 +16,23 @@ namespace Squidex.Infrastructure.Reflection { public static class SimpleMapper { + private sealed class StringConversionPropertyMapper : PropertyMapper + { + public StringConversionPropertyMapper( + IPropertyAccessor sourceAccessor, + IPropertyAccessor targetAccessor) + : base(sourceAccessor, targetAccessor) + { + } + + public override void MapProperty(object source, object target, CultureInfo culture) + { + var value = GetValue(source); + + SetValue(target, value?.ToString()); + } + } + private sealed class ConversionPropertyMapper : PropertyMapper { private readonly Type targetType; @@ -38,21 +55,15 @@ namespace Squidex.Infrastructure.Reflection return; } - object converted; try { - converted = Convert.ChangeType(value, targetType, culture); + var converted = Convert.ChangeType(value, targetType, culture); SetValue(target, converted); } - catch (InvalidCastException) + catch { - if (targetType == typeof(string)) - { - converted = value.ToString(); - - SetValue(target, converted); - } + return; } } } @@ -120,7 +131,13 @@ namespace Squidex.Infrastructure.Reflection new PropertyAccessor(sourceClassType, sourceProperty), new PropertyAccessor(targetClassType, targetProperty))); } - else if (targetType.Implements()) + else if (targetType == typeof(string)) + { + Mappers.Add(new StringConversionPropertyMapper( + new PropertyAccessor(sourceClassType, sourceProperty), + new PropertyAccessor(targetClassType, targetProperty))); + } + else if (sourceType.Implements()) { Mappers.Add(new ConversionPropertyMapper( new PropertyAccessor(sourceClassType, sourceProperty), diff --git a/tests/Squidex.Infrastructure.Tests/Reflection/SimpleMapperTests.cs b/tests/Squidex.Infrastructure.Tests/Reflection/SimpleMapperTests.cs index a3056bcc8..3b044b1e3 100644 --- a/tests/Squidex.Infrastructure.Tests/Reflection/SimpleMapperTests.cs +++ b/tests/Squidex.Infrastructure.Tests/Reflection/SimpleMapperTests.cs @@ -6,111 +6,158 @@ // ========================================================================== using System; -using NodaTime; +using System.Diagnostics; using Xunit; namespace Squidex.Infrastructure.Reflection { public class SimpleMapperTests { - public class MyClass1Base + public class Class1Base { - public Guid MappedGuid { get; set; } - - public string MappedString { get; set; } + public T1 P1 { get; set; } + } - public string MappedNull { get; set; } + public class Class1 : Class1Base + { + public T2 P2 { get; set; } + } - public long MappedNumber { get; set; } + public class Class2Base + { + public T2 P2 { get; set; } + } - public long WrongType1 { get; set; } + public class Class2 : Class2Base + { + public T3 P3 { get; set; } + } - public long WrongType2 { get; set; } + public class Readonly + { + public T P1 { get; } } - public class MyClass1 : MyClass1Base + public class Writeonly { - public string UnmappedString { get; set; } + public T P1 + { + set { Debug.WriteLine(value); } + } } - public class MyClass2Base + [Fact] + public void Should_throw_exception_if_mapping_with_null_source() { - public string MappedString { get; protected set; } + Assert.Throws(() => SimpleMapper.Map((Class2)null, new Class2())); + } - public int MappedNull { get; set; } + [Fact] + public void Should_throw_exception_if_mapping_with_null_target() + { + Assert.Throws(() => SimpleMapper.Map(new Class2(), (Class2)null)); + } - public int MappedNumber { get; set; } + [Fact] + public void Should_map_to_same_type() + { + var obj1 = new Class1 + { + P1 = 6, + P2 = 8 + }; + var obj2 = SimpleMapper.Map(obj1, new Class2()); - public string MappedGuid { get; set; } + Assert.Equal(8, obj2.P2); + Assert.Equal(0, obj2.P3); } - public class MyClass2 : MyClass2Base + [Fact] + public void Should_map_all_properties() { - public string UnmappedString + var obj1 = new Class1 { - get { return "Value"; } - } - - public Instant WrongType1 { get; set; } + P1 = 6, + P2 = 8 + }; + var obj2 = SimpleMapper.Map(obj1, new Class1()); - public Duration WrongType2 { get; set; } + Assert.Equal(6, obj2.P1); + Assert.Equal(8, obj2.P2); } [Fact] - public void Should_throw_exception_if_mapping_with_null_source() + public void Should_map_to_convertible_type() { - Assert.Throws(() => SimpleMapper.Map((MyClass1)null, new MyClass2())); + var obj1 = new Class1 + { + P1 = 6, + P2 = 8 + }; + var obj2 = SimpleMapper.Map(obj1, new Class2()); + + Assert.Equal(8, obj2.P2); + Assert.Equal(0, obj2.P3); } [Fact] - public void Should_throw_exception_if_mapping_with_null_target() + public void Should_map_when_convertible_is_null() { - Assert.Throws(() => SimpleMapper.Map(new MyClass1(), (MyClass2)null)); + var obj1 = new Class1 + { + P1 = null, + P2 = null + }; + var obj2 = SimpleMapper.Map(obj1, new Class1()); + + Assert.Equal(0, obj2.P1); + Assert.Equal(0, obj2.P2); } [Fact] - public void Should_map_to_type() + public void Should_convert_to_string() { - var class1 = new MyClass1 + var obj1 = new Class1 { - UnmappedString = Guid.NewGuid().ToString(), - MappedString = Guid.NewGuid().ToString(), - MappedNumber = 123, - MappedGuid = Guid.NewGuid() + P1 = new RefToken("user", "1"), + P2 = new RefToken("user", "2") }; + var obj2 = SimpleMapper.Map(obj1, new Class2()); - var class2 = SimpleMapper.Map(class1); - - AssertObjectEquality(class1, class2); + Assert.Equal("user:2", obj2.P2); + Assert.Null(obj2.P3); } [Fact] - public void Should_map_between_types() + public void Should_return_default_if_conversion_failed() { - var class1 = new MyClass1 + var obj1 = new Class1 { - UnmappedString = Guid.NewGuid().ToString(), - MappedString = Guid.NewGuid().ToString(), - MappedNumber = 123, - MappedGuid = Guid.NewGuid() + P1 = long.MaxValue, + P2 = long.MaxValue }; - var class2 = new MyClass2(); - - SimpleMapper.Map(class1, class2); + var obj2 = SimpleMapper.Map(obj1, new Class2()); - AssertObjectEquality(class1, class2); + Assert.Equal(0, obj2.P2); + Assert.Equal(0, obj2.P3); } - private static void AssertObjectEquality(MyClass1 class1, MyClass2 class2) + [Fact] + public void Should_ignore_write_only() { - Assert.Equal(class1.MappedString, class2.MappedString); - Assert.Equal(class1.MappedNumber, class2.MappedNumber); - Assert.Equal(class1.MappedGuid.ToString(), class2.MappedGuid); + var obj1 = new Writeonly(); + var obj2 = SimpleMapper.Map(obj1, new Class1()); + + Assert.Equal(0, obj2.P1); + } - Assert.NotEqual(class1.UnmappedString, class2.UnmappedString); + [Fact] + public void Should_ignore_read_only() + { + var obj1 = new Class1 { P1 = 10 }; + var obj2 = SimpleMapper.Map(obj1, new Readonly()); - Assert.Equal(0L, class1.WrongType1); - Assert.Equal(0L, class1.WrongType2); + Assert.Equal(0, obj2.P1); } } }