Browse Source

Merge pull request #251 from Squidex/orleans-preparation

Mapper improved to get rid of exceptions.
pull/252/head
Sebastian Stehle 8 years ago
committed by GitHub
parent
commit
d0e725f1ae
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 37
      src/Squidex.Infrastructure/Reflection/SimpleMapper.cs
  2. 153
      tests/Squidex.Infrastructure.Tests/Reflection/SimpleMapperTests.cs

37
src/Squidex.Infrastructure/Reflection/SimpleMapper.cs

@ -16,6 +16,23 @@ namespace Squidex.Infrastructure.Reflection
{ {
public static class SimpleMapper 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 sealed class ConversionPropertyMapper : PropertyMapper
{ {
private readonly Type targetType; private readonly Type targetType;
@ -38,21 +55,15 @@ namespace Squidex.Infrastructure.Reflection
return; return;
} }
object converted;
try try
{ {
converted = Convert.ChangeType(value, targetType, culture); var converted = Convert.ChangeType(value, targetType, culture);
SetValue(target, converted); SetValue(target, converted);
} }
catch (InvalidCastException) catch
{ {
if (targetType == typeof(string)) return;
{
converted = value.ToString();
SetValue(target, converted);
}
} }
} }
} }
@ -120,7 +131,13 @@ namespace Squidex.Infrastructure.Reflection
new PropertyAccessor(sourceClassType, sourceProperty), new PropertyAccessor(sourceClassType, sourceProperty),
new PropertyAccessor(targetClassType, targetProperty))); new PropertyAccessor(targetClassType, targetProperty)));
} }
else if (targetType.Implements<IConvertible>()) else if (targetType == typeof(string))
{
Mappers.Add(new StringConversionPropertyMapper(
new PropertyAccessor(sourceClassType, sourceProperty),
new PropertyAccessor(targetClassType, targetProperty)));
}
else if (sourceType.Implements<IConvertible>())
{ {
Mappers.Add(new ConversionPropertyMapper( Mappers.Add(new ConversionPropertyMapper(
new PropertyAccessor(sourceClassType, sourceProperty), new PropertyAccessor(sourceClassType, sourceProperty),

153
tests/Squidex.Infrastructure.Tests/Reflection/SimpleMapperTests.cs

@ -6,111 +6,158 @@
// ========================================================================== // ==========================================================================
using System; using System;
using NodaTime; using System.Diagnostics;
using Xunit; using Xunit;
namespace Squidex.Infrastructure.Reflection namespace Squidex.Infrastructure.Reflection
{ {
public class SimpleMapperTests public class SimpleMapperTests
{ {
public class MyClass1Base public class Class1Base<T1>
{ {
public Guid MappedGuid { get; set; } public T1 P1 { get; set; }
}
public string MappedString { get; set; }
public string MappedNull { get; set; } public class Class1<T1, T2> : Class1Base<T1>
{
public T2 P2 { get; set; }
}
public long MappedNumber { get; set; } public class Class2Base<T2>
{
public T2 P2 { get; set; }
}
public long WrongType1 { get; set; } public class Class2<T2, T3> : Class2Base<T2>
{
public T3 P3 { get; set; }
}
public long WrongType2 { get; set; } public class Readonly<T>
{
public T P1 { get; }
} }
public class MyClass1 : MyClass1Base public class Writeonly<T>
{ {
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<ArgumentNullException>(() => SimpleMapper.Map((Class2<int, int>)null, new Class2<int, int>()));
}
public int MappedNull { get; set; } [Fact]
public void Should_throw_exception_if_mapping_with_null_target()
{
Assert.Throws<ArgumentNullException>(() => SimpleMapper.Map(new Class2<int, int>(), (Class2<int, int>)null));
}
public int MappedNumber { get; set; } [Fact]
public void Should_map_to_same_type()
{
var obj1 = new Class1<int, int>
{
P1 = 6,
P2 = 8
};
var obj2 = SimpleMapper.Map(obj1, new Class2<int, int>());
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<int, int>
{ {
get { return "Value"; } P1 = 6,
} P2 = 8
};
public Instant WrongType1 { get; set; } var obj2 = SimpleMapper.Map(obj1, new Class1<int, int>());
public Duration WrongType2 { get; set; } Assert.Equal(6, obj2.P1);
Assert.Equal(8, obj2.P2);
} }
[Fact] [Fact]
public void Should_throw_exception_if_mapping_with_null_source() public void Should_map_to_convertible_type()
{ {
Assert.Throws<ArgumentNullException>(() => SimpleMapper.Map((MyClass1)null, new MyClass2())); var obj1 = new Class1<long, long>
{
P1 = 6,
P2 = 8
};
var obj2 = SimpleMapper.Map(obj1, new Class2<int, int>());
Assert.Equal(8, obj2.P2);
Assert.Equal(0, obj2.P3);
} }
[Fact] [Fact]
public void Should_throw_exception_if_mapping_with_null_target() public void Should_map_when_convertible_is_null()
{ {
Assert.Throws<ArgumentNullException>(() => SimpleMapper.Map(new MyClass1(), (MyClass2)null)); var obj1 = new Class1<int?, int?>
{
P1 = null,
P2 = null
};
var obj2 = SimpleMapper.Map(obj1, new Class1<int, int>());
Assert.Equal(0, obj2.P1);
Assert.Equal(0, obj2.P2);
} }
[Fact] [Fact]
public void Should_map_to_type() public void Should_convert_to_string()
{ {
var class1 = new MyClass1 var obj1 = new Class1<RefToken, RefToken>
{ {
UnmappedString = Guid.NewGuid().ToString(), P1 = new RefToken("user", "1"),
MappedString = Guid.NewGuid().ToString(), P2 = new RefToken("user", "2")
MappedNumber = 123,
MappedGuid = Guid.NewGuid()
}; };
var obj2 = SimpleMapper.Map(obj1, new Class2<string, string>());
var class2 = SimpleMapper.Map<MyClass1, MyClass2>(class1); Assert.Equal("user:2", obj2.P2);
Assert.Null(obj2.P3);
AssertObjectEquality(class1, class2);
} }
[Fact] [Fact]
public void Should_map_between_types() public void Should_return_default_if_conversion_failed()
{ {
var class1 = new MyClass1 var obj1 = new Class1<long, long>
{ {
UnmappedString = Guid.NewGuid().ToString(), P1 = long.MaxValue,
MappedString = Guid.NewGuid().ToString(), P2 = long.MaxValue
MappedNumber = 123,
MappedGuid = Guid.NewGuid()
}; };
var class2 = new MyClass2(); var obj2 = SimpleMapper.Map(obj1, new Class2<int, int>());
SimpleMapper.Map(class1, 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); var obj1 = new Writeonly<int>();
Assert.Equal(class1.MappedNumber, class2.MappedNumber); var obj2 = SimpleMapper.Map(obj1, new Class1<int, int>());
Assert.Equal(class1.MappedGuid.ToString(), class2.MappedGuid);
Assert.Equal(0, obj2.P1);
}
Assert.NotEqual(class1.UnmappedString, class2.UnmappedString); [Fact]
public void Should_ignore_read_only()
{
var obj1 = new Class1<int, int> { P1 = 10 };
var obj2 = SimpleMapper.Map(obj1, new Readonly<int>());
Assert.Equal(0L, class1.WrongType1); Assert.Equal(0, obj2.P1);
Assert.Equal(0L, class1.WrongType2);
} }
} }
} }

Loading…
Cancel
Save