From ce3d4e339c8c2cfdad1b74736037e2416784ef45 Mon Sep 17 00:00:00 2001 From: Daniel Cronqvist Date: Sat, 31 Aug 2024 19:56:44 +0200 Subject: [PATCH] Rename parts of the property mapping API and simplify --- .../Properties/HasPropertiesBaseTests.cs | 66 +++++++++++++++---- src/DotTiled/Properties/IHasProperties.cs | 39 ++++++++--- 2 files changed, 82 insertions(+), 23 deletions(-) diff --git a/src/DotTiled.Tests/Properties/HasPropertiesBaseTests.cs b/src/DotTiled.Tests/Properties/HasPropertiesBaseTests.cs index 4e53b57..ea7d375 100644 --- a/src/DotTiled.Tests/Properties/HasPropertiesBaseTests.cs +++ b/src/DotTiled.Tests/Properties/HasPropertiesBaseTests.cs @@ -21,7 +21,7 @@ public class HasPropertiesBaseTests } [Fact] - public void GetMappedProperty_PropertyNotFound_ThrowsKeyNotFoundException() + public void MapClassPropertyTo_PropertyNotFound_ThrowsKeyNotFoundException() { // Arrange List props = [ @@ -35,15 +35,25 @@ public class HasPropertiesBaseTests ]; var hasProperties = new TestHasProperties(props); - // Act - var act = () => hasProperties.GetMappedProperty("ClassInObject"); - - // Assert - Assert.Throws(act); + // Act & Assert + _ = Assert.Throws(() => hasProperties.MapClassPropertyTo("ClassInObject")); } [Fact] - public void GetMappedProperty_AllBasicValidProperties_ReturnsMappedProperty() + public void MapClassPropertyTo_PropertyIsNotClassProperty_ThrowsInvalidCastException() + { + // Arrange + List props = [ + new StringProperty { Name = "ClassInObject", Value = "Test" } + ]; + var hasProperties = new TestHasProperties(props); + + // Act & Assert + _ = Assert.Throws(() => hasProperties.MapClassPropertyTo("ClassInObject")); + } + + [Fact] + public void MapClassPropertyTo_AllBasicValidProperties_ReturnsMappedProperty() { // Arrange List props = [ @@ -64,7 +74,7 @@ public class HasPropertiesBaseTests var hasProperties = new TestHasProperties(props); // Act - var mappedProperty = hasProperties.GetMappedProperty("ClassInObject"); + var mappedProperty = hasProperties.MapClassPropertyTo("ClassInObject"); // Assert Assert.True(mappedProperty.MapToBool); @@ -83,7 +93,7 @@ public class HasPropertiesBaseTests } [Fact] - public void GetMappedProperty_NestedMapTo_ReturnsMappedProperty() + public void MapClassPropertyTo_NestedMapTo_ReturnsMappedProperty() { // Arrange List props = [ @@ -111,7 +121,7 @@ public class HasPropertiesBaseTests var hasProperties = new TestHasProperties(props); // Act - var mappedProperty = hasProperties.GetMappedProperty("ClassInObject"); + var mappedProperty = hasProperties.MapClassPropertyTo("ClassInObject"); // Assert Assert.Equal("Test", mappedProperty.NestedMapToString); @@ -137,7 +147,7 @@ public class HasPropertiesBaseTests } [Fact] - public void GetMappedProperty_EnumProperty_ReturnsMappedProperty() + public void MapClassPropertyTo_EnumProperty_ReturnsMappedProperty() { // Arrange List props = [ @@ -152,7 +162,7 @@ public class HasPropertiesBaseTests var hasProperties = new TestHasProperties(props); // Act - var mappedProperty = hasProperties.GetMappedProperty("ClassInObject"); + var mappedProperty = hasProperties.MapClassPropertyTo("ClassInObject"); // Assert Assert.Equal(TestEnum.TestValue1, mappedProperty.EnumMapToEnum); @@ -171,7 +181,7 @@ public class HasPropertiesBaseTests } [Fact] - public void GetMappedProperty_EnumWithFlagsProperty_ReturnsMappedProperty() + public void MapClassPropertyTo_EnumWithFlagsProperty_ReturnsMappedProperty() { // Arrange List props = [ @@ -186,9 +196,37 @@ public class HasPropertiesBaseTests var hasProperties = new TestHasProperties(props); // Act - var mappedProperty = hasProperties.GetMappedProperty("ClassInObject"); + var mappedProperty = hasProperties.MapClassPropertyTo("ClassInObject"); // Assert Assert.Equal(TestEnumWithFlags.TestValue1 | TestEnumWithFlags.TestValue2, mappedProperty.EnumWithFlagsMapToEnum); } + + [Fact] + public void MapPropertiesTo_WithProperties_ReturnsMappedProperty() + { + // Arrange + List 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(); + + // 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); + } } diff --git a/src/DotTiled/Properties/IHasProperties.cs b/src/DotTiled/Properties/IHasProperties.cs index 748e2b5..cd413dd 100644 --- a/src/DotTiled/Properties/IHasProperties.cs +++ b/src/DotTiled/Properties/IHasProperties.cs @@ -32,7 +32,20 @@ public interface IHasProperties /// The property with the specified name. T GetProperty(string name) where T : IProperty; - T GetMappedProperty(string name) where T : new(); + /// + /// Maps a class property to a new instance of the specified type using reflection. + /// + /// + /// The property which you want to map to a class + /// + T MapClassPropertyTo(string name) where T : new(); + + /// + /// Maps all properties in this object to a new instance of the specified type using reflection. + /// + /// + /// + T MapPropertiesTo() where T : new(); } /// @@ -72,17 +85,25 @@ public abstract class HasPropertiesBase : IHasProperties return false; } - public T GetMappedProperty(string name) where T : new() + /// + public T MapClassPropertyTo(string name) where T : new() { - var property = GetProperty(name); - return CreateMappedInstance(property); + var classProperty = GetProperty(name); + return CreateMappedInstance(classProperty.GetProperties()); } - private static object CreatedMappedInstance(Type type, ClassProperty classProperty) + /// + public T MapPropertiesTo() where T : new() { - var instance = Activator.CreateInstance(type); + var properties = GetProperties(); + return CreateMappedInstance(properties); + } - foreach (var prop in classProperty.Value) + private static object CreatedMappedInstance(Type type, IList 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) throw new KeyNotFoundException($"Property '{prop.Name}' not found in '{type.Name}'."); @@ -112,7 +133,7 @@ public abstract class HasPropertiesBase : IHasProperties break; case ClassProperty classProp: var subClassProp = type.GetProperty(prop.Name); - subClassProp?.SetValue(instance, CreatedMappedInstance(subClassProp.PropertyType, classProp)); + subClassProp?.SetValue(instance, CreatedMappedInstance(subClassProp.PropertyType, classProp.GetProperties())); break; case EnumProperty enumProp: var enumPropInClass = type.GetProperty(prop.Name); @@ -127,5 +148,5 @@ public abstract class HasPropertiesBase : IHasProperties return instance; } - private static T CreateMappedInstance(ClassProperty classProperty) where T : new() => (T)CreatedMappedInstance(typeof(T), classProperty); + private static T CreateMappedInstance(IList properties) where T : new() => (T)CreatedMappedInstance(typeof(T), properties); }