Rename parts of the property mapping API and simplify

This commit is contained in:
Daniel Cronqvist 2024-08-31 19:56:44 +02:00
parent fda0922dcc
commit ce3d4e339c
2 changed files with 82 additions and 23 deletions

View file

@ -21,7 +21,7 @@ public class HasPropertiesBaseTests
} }
[Fact] [Fact]
public void GetMappedProperty_PropertyNotFound_ThrowsKeyNotFoundException() public void MapClassPropertyTo_PropertyNotFound_ThrowsKeyNotFoundException()
{ {
// Arrange // Arrange
List<IProperty> props = [ List<IProperty> props = [
@ -35,15 +35,25 @@ public class HasPropertiesBaseTests
]; ];
var hasProperties = new TestHasProperties(props); var hasProperties = new TestHasProperties(props);
// Act // Act & Assert
var act = () => hasProperties.GetMappedProperty<MapTo>("ClassInObject"); _ = Assert.Throws<KeyNotFoundException>(() => hasProperties.MapClassPropertyTo<MapTo>("ClassInObject"));
// Assert
Assert.Throws<KeyNotFoundException>(act);
} }
[Fact] [Fact]
public void GetMappedProperty_AllBasicValidProperties_ReturnsMappedProperty() public void MapClassPropertyTo_PropertyIsNotClassProperty_ThrowsInvalidCastException()
{
// Arrange
List<IProperty> props = [
new StringProperty { Name = "ClassInObject", Value = "Test" }
];
var hasProperties = new TestHasProperties(props);
// Act & Assert
_ = Assert.Throws<InvalidCastException>(() => hasProperties.MapClassPropertyTo<MapTo>("ClassInObject"));
}
[Fact]
public void MapClassPropertyTo_AllBasicValidProperties_ReturnsMappedProperty()
{ {
// Arrange // Arrange
List<IProperty> props = [ List<IProperty> props = [
@ -64,7 +74,7 @@ public class HasPropertiesBaseTests
var hasProperties = new TestHasProperties(props); var hasProperties = new TestHasProperties(props);
// Act // Act
var mappedProperty = hasProperties.GetMappedProperty<MapTo>("ClassInObject"); var mappedProperty = hasProperties.MapClassPropertyTo<MapTo>("ClassInObject");
// Assert // Assert
Assert.True(mappedProperty.MapToBool); Assert.True(mappedProperty.MapToBool);
@ -83,7 +93,7 @@ public class HasPropertiesBaseTests
} }
[Fact] [Fact]
public void GetMappedProperty_NestedMapTo_ReturnsMappedProperty() public void MapClassPropertyTo_NestedMapTo_ReturnsMappedProperty()
{ {
// Arrange // Arrange
List<IProperty> props = [ List<IProperty> props = [
@ -111,7 +121,7 @@ public class HasPropertiesBaseTests
var hasProperties = new TestHasProperties(props); var hasProperties = new TestHasProperties(props);
// Act // Act
var mappedProperty = hasProperties.GetMappedProperty<NestedMapTo>("ClassInObject"); var mappedProperty = hasProperties.MapClassPropertyTo<NestedMapTo>("ClassInObject");
// Assert // Assert
Assert.Equal("Test", mappedProperty.NestedMapToString); Assert.Equal("Test", mappedProperty.NestedMapToString);
@ -137,7 +147,7 @@ public class HasPropertiesBaseTests
} }
[Fact] [Fact]
public void GetMappedProperty_EnumProperty_ReturnsMappedProperty() public void MapClassPropertyTo_EnumProperty_ReturnsMappedProperty()
{ {
// Arrange // Arrange
List<IProperty> props = [ List<IProperty> props = [
@ -152,7 +162,7 @@ public class HasPropertiesBaseTests
var hasProperties = new TestHasProperties(props); var hasProperties = new TestHasProperties(props);
// Act // Act
var mappedProperty = hasProperties.GetMappedProperty<EnumMapTo>("ClassInObject"); var mappedProperty = hasProperties.MapClassPropertyTo<EnumMapTo>("ClassInObject");
// Assert // Assert
Assert.Equal(TestEnum.TestValue1, mappedProperty.EnumMapToEnum); Assert.Equal(TestEnum.TestValue1, mappedProperty.EnumMapToEnum);
@ -171,7 +181,7 @@ public class HasPropertiesBaseTests
} }
[Fact] [Fact]
public void GetMappedProperty_EnumWithFlagsProperty_ReturnsMappedProperty() public void MapClassPropertyTo_EnumWithFlagsProperty_ReturnsMappedProperty()
{ {
// Arrange // Arrange
List<IProperty> props = [ List<IProperty> props = [
@ -186,9 +196,37 @@ public class HasPropertiesBaseTests
var hasProperties = new TestHasProperties(props); var hasProperties = new TestHasProperties(props);
// Act // Act
var mappedProperty = hasProperties.GetMappedProperty<EnumWithFlagsMapTo>("ClassInObject"); var mappedProperty = hasProperties.MapClassPropertyTo<EnumWithFlagsMapTo>("ClassInObject");
// Assert // Assert
Assert.Equal(TestEnumWithFlags.TestValue1 | TestEnumWithFlags.TestValue2, mappedProperty.EnumWithFlagsMapToEnum); Assert.Equal(TestEnumWithFlags.TestValue1 | TestEnumWithFlags.TestValue2, mappedProperty.EnumWithFlagsMapToEnum);
} }
[Fact]
public void MapPropertiesTo_WithProperties_ReturnsMappedProperty()
{
// Arrange
List<IProperty> props = [
new BoolProperty { Name = "MapToBool", Value = true },
new ColorProperty { Name = "MapToColor", Value = Color.Parse("#FF0000FF", CultureInfo.InvariantCulture) },
new FloatProperty { Name = "MapToFloat", Value = 1.0f },
new StringProperty { Name = "MapToFile", Value = "Test" },
new IntProperty { Name = "MapToInt", Value = 1 },
new IntProperty { Name = "MapToObject", Value = 1 },
new StringProperty { Name = "MapToString", Value = "Test" },
];
var hasProperties = new TestHasProperties(props);
// Act
var mappedProperty = hasProperties.MapPropertiesTo<MapTo>();
// Assert
Assert.True(mappedProperty.MapToBool);
Assert.Equal(Color.Parse("#FF0000FF", CultureInfo.InvariantCulture), mappedProperty.MapToColor);
Assert.Equal(1.0f, mappedProperty.MapToFloat);
Assert.Equal("Test", mappedProperty.MapToFile);
Assert.Equal(1, mappedProperty.MapToInt);
Assert.Equal(1, mappedProperty.MapToObject);
Assert.Equal("Test", mappedProperty.MapToString);
}
} }

View file

@ -32,7 +32,20 @@ public interface IHasProperties
/// <returns>The property with the specified name.</returns> /// <returns>The property with the specified name.</returns>
T GetProperty<T>(string name) where T : IProperty; T GetProperty<T>(string name) where T : IProperty;
T GetMappedProperty<T>(string name) where T : new(); /// <summary>
/// Maps a class property to a new instance of the specified type using reflection.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name">The property which you want to map to a class</param>
/// <returns></returns>
T MapClassPropertyTo<T>(string name) where T : new();
/// <summary>
/// Maps all properties in this object to a new instance of the specified type using reflection.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
T MapPropertiesTo<T>() where T : new();
} }
/// <summary> /// <summary>
@ -72,17 +85,25 @@ public abstract class HasPropertiesBase : IHasProperties
return false; return false;
} }
public T GetMappedProperty<T>(string name) where T : new() /// <inheritdoc/>
public T MapClassPropertyTo<T>(string name) where T : new()
{ {
var property = GetProperty<ClassProperty>(name); var classProperty = GetProperty<ClassProperty>(name);
return CreateMappedInstance<T>(property); return CreateMappedInstance<T>(classProperty.GetProperties());
} }
private static object CreatedMappedInstance(Type type, ClassProperty classProperty) /// <inheritdoc/>
public T MapPropertiesTo<T>() where T : new()
{ {
var instance = Activator.CreateInstance(type); var properties = GetProperties();
return CreateMappedInstance<T>(properties);
}
foreach (var prop in classProperty.Value) private static object CreatedMappedInstance(Type type, IList<IProperty> properties)
{
var instance = Activator.CreateInstance(type) ?? throw new InvalidOperationException($"Failed to create instance of '{type.Name}'.");
foreach (var prop in properties)
{ {
if (type.GetProperty(prop.Name) == null) if (type.GetProperty(prop.Name) == null)
throw new KeyNotFoundException($"Property '{prop.Name}' not found in '{type.Name}'."); throw new KeyNotFoundException($"Property '{prop.Name}' not found in '{type.Name}'.");
@ -112,7 +133,7 @@ public abstract class HasPropertiesBase : IHasProperties
break; break;
case ClassProperty classProp: case ClassProperty classProp:
var subClassProp = type.GetProperty(prop.Name); var subClassProp = type.GetProperty(prop.Name);
subClassProp?.SetValue(instance, CreatedMappedInstance(subClassProp.PropertyType, classProp)); subClassProp?.SetValue(instance, CreatedMappedInstance(subClassProp.PropertyType, classProp.GetProperties()));
break; break;
case EnumProperty enumProp: case EnumProperty enumProp:
var enumPropInClass = type.GetProperty(prop.Name); var enumPropInClass = type.GetProperty(prop.Name);
@ -127,5 +148,5 @@ public abstract class HasPropertiesBase : IHasProperties
return instance; return instance;
} }
private static T CreateMappedInstance<T>(ClassProperty classProperty) where T : new() => (T)CreatedMappedInstance(typeof(T), classProperty); private static T CreateMappedInstance<T>(IList<IProperty> properties) where T : new() => (T)CreatedMappedInstance(typeof(T), properties);
} }