From 1027b922fe6678962962f5871ed7c3fc540c91d2 Mon Sep 17 00:00:00 2001 From: Kat Date: Tue, 19 Nov 2024 03:08:04 -0800 Subject: [PATCH 1/2] Enum properties in CustomClassDefinition.FromClass --- .../CustomTypes/FromTypeUsedInLoaderTests.cs | 23 +++++++++++++++++-- .../CustomTypes/CustomClassDefinition.cs | 14 +++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/DotTiled.Tests/IntegrationTests/CustomTypes/FromTypeUsedInLoaderTests.cs b/src/DotTiled.Tests/IntegrationTests/CustomTypes/FromTypeUsedInLoaderTests.cs index dae9464..87c9948 100644 --- a/src/DotTiled.Tests/IntegrationTests/CustomTypes/FromTypeUsedInLoaderTests.cs +++ b/src/DotTiled.Tests/IntegrationTests/CustomTypes/FromTypeUsedInLoaderTests.cs @@ -5,10 +5,25 @@ namespace DotTiled.Tests; public class FromTypeUsedInLoaderTests { + private enum TestEnum + { + A, + B, + C + } + [Flags] + private enum TestFlags + { + A = 0b001, + B = 0b010, + C = 0b100 + } private sealed class TestClass { public string Name { get; set; } = "John Doe"; public int Age { get; set; } = 42; + public TestEnum Enum { get; set; } = TestEnum.A; + public TestFlags Flags { get; set; } = TestFlags.B | TestFlags.C; } [Fact] @@ -82,7 +97,9 @@ public class FromTypeUsedInLoaderTests ], Properties = [ new StringProperty { Name = "Name", Value = "John Doe" }, - new IntProperty { Name = "Age", Value = 42 } + new IntProperty { Name = "Age", Value = 42 }, + new EnumProperty { Name = "Enum", PropertyType = "TestEnum", Value = new HashSet { "A" } }, + new EnumProperty { Name = "Flags", PropertyType = "TestFlags", Value = new HashSet { "B", "C" } } ] }; @@ -167,7 +184,9 @@ public class FromTypeUsedInLoaderTests ], Properties = [ new StringProperty { Name = "Name", Value = "John Doe" }, - new IntProperty { Name = "Age", Value = 42 } + new IntProperty { Name = "Age", Value = 42 }, + new EnumProperty { Name = "Enum", PropertyType = "TestEnum", Value = new HashSet { "A" } }, + new EnumProperty { Name = "Flags", PropertyType = "TestFlags", Value = new HashSet { "B", "C" } } ] }; diff --git a/src/DotTiled/Properties/CustomTypes/CustomClassDefinition.cs b/src/DotTiled/Properties/CustomTypes/CustomClassDefinition.cs index 83e0fbe..b674f48 100644 --- a/src/DotTiled/Properties/CustomTypes/CustomClassDefinition.cs +++ b/src/DotTiled/Properties/CustomTypes/CustomClassDefinition.cs @@ -165,6 +165,20 @@ public class CustomClassDefinition : HasPropertiesBase, ICustomTypeDefinition return new IntProperty { Name = propertyInfo.Name, Value = (int)propertyInfo.GetValue(instance) }; case Type t when t.IsClass: return new ClassProperty { Name = propertyInfo.Name, PropertyType = t.Name, Value = GetNestedProperties(propertyInfo.PropertyType, propertyInfo.GetValue(instance)) }; + case Type t when t.IsEnum: + var isFlags = t.GetCustomAttributes(typeof(FlagsAttribute), false).Length != 0; + + if (isFlags) + { + ISet values = new HashSet(); + foreach (var value in t.GetEnumValues()) + { + if (((int)value & (int)propertyInfo.GetValue(instance)) != 0) values.Add(t.GetEnumName(value)); + } + return new EnumProperty { Name = propertyInfo.Name, PropertyType = t.Name, Value = values }; + } + + return new EnumProperty { Name = propertyInfo.Name, PropertyType = t.Name, Value = new HashSet { t.GetEnumName(propertyInfo.GetValue(instance)) } }; default: break; } From 7a7f360e2238ab381d6e375c2f9a5f91fa3eb50c Mon Sep 17 00:00:00 2001 From: Kat Date: Wed, 20 Nov 2024 05:11:45 -0800 Subject: [PATCH 2/2] Implement requested changes --- .../CustomTypes/FromTypeUsedInLoaderTests.cs | 115 ++++++++++++++---- .../CustomTypes/CustomClassDefinitionTests.cs | 31 +++++ .../CustomTypes/CustomClassDefinition.cs | 19 ++- 3 files changed, 133 insertions(+), 32 deletions(-) diff --git a/src/DotTiled.Tests/IntegrationTests/CustomTypes/FromTypeUsedInLoaderTests.cs b/src/DotTiled.Tests/IntegrationTests/CustomTypes/FromTypeUsedInLoaderTests.cs index 87c9948..c0d580f 100644 --- a/src/DotTiled.Tests/IntegrationTests/CustomTypes/FromTypeUsedInLoaderTests.cs +++ b/src/DotTiled.Tests/IntegrationTests/CustomTypes/FromTypeUsedInLoaderTests.cs @@ -5,25 +5,10 @@ namespace DotTiled.Tests; public class FromTypeUsedInLoaderTests { - private enum TestEnum - { - A, - B, - C - } - [Flags] - private enum TestFlags - { - A = 0b001, - B = 0b010, - C = 0b100 - } private sealed class TestClass { public string Name { get; set; } = "John Doe"; public int Age { get; set; } = 42; - public TestEnum Enum { get; set; } = TestEnum.A; - public TestFlags Flags { get; set; } = TestFlags.B | TestFlags.C; } [Fact] @@ -97,9 +82,7 @@ public class FromTypeUsedInLoaderTests ], Properties = [ new StringProperty { Name = "Name", Value = "John Doe" }, - new IntProperty { Name = "Age", Value = 42 }, - new EnumProperty { Name = "Enum", PropertyType = "TestEnum", Value = new HashSet { "A" } }, - new EnumProperty { Name = "Flags", PropertyType = "TestFlags", Value = new HashSet { "B", "C" } } + new IntProperty { Name = "Age", Value = 42 } ] }; @@ -184,9 +167,99 @@ public class FromTypeUsedInLoaderTests ], Properties = [ new StringProperty { Name = "Name", Value = "John Doe" }, - new IntProperty { Name = "Age", Value = 42 }, - new EnumProperty { Name = "Enum", PropertyType = "TestEnum", Value = new HashSet { "A" } }, - new EnumProperty { Name = "Flags", PropertyType = "TestFlags", Value = new HashSet { "B", "C" } } + new IntProperty { Name = "Age", Value = 42 } + ] + }; + + // Act + var result = loader.LoadMap("map.tmx"); + + // Assert + DotTiledAssert.AssertMap(expectedMap, result); + } + + private enum TestEnum + { + Value1, + Value2 + } + + private sealed class TestClassWithEnum + { + public TestEnum Enum { get; set; } = TestEnum.Value1; + } + + [Fact] + public void LoadMap_MapHasClassWithEnumAndClassIsDefined_ReturnsCorrectMap() + { + // Arrange + var resourceReader = Substitute.For(); + resourceReader.Read("map.tmx").Returns( + """ + + + + + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0 + + + + """); + var classDefinition = CustomClassDefinition.FromClass(); + var loader = Loader.DefaultWith( + resourceReader: resourceReader, + customTypeDefinitions: [classDefinition]); + var expectedMap = new Map + { + Class = "TestClassWithEnum", + Orientation = MapOrientation.Orthogonal, + Width = 5, + Height = 5, + TileWidth = 32, + TileHeight = 32, + Infinite = false, + ParallaxOriginX = 0, + ParallaxOriginY = 0, + RenderOrder = RenderOrder.RightDown, + CompressionLevel = -1, + BackgroundColor = new Color { R = 0, G = 0, B = 0, A = 0 }, + Version = "1.10", + TiledVersion = "1.11.0", + NextLayerID = 2, + NextObjectID = 1, + Layers = [ + new TileLayer + { + ID = 1, + Name = "Tile Layer 1", + Width = 5, + Height = 5, + Data = new Data + { + Encoding = DataEncoding.Csv, + GlobalTileIDs = new Optional([ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 + ]), + FlippingFlags = new Optional([ + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, + FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None, FlippingFlags.None + ]) + } + } + ], + Properties = [ + new EnumProperty { Name = "Enum", PropertyType = "TestEnum", Value = new HashSet { "Value1" } } ] }; diff --git a/src/DotTiled.Tests/UnitTests/Properties/CustomTypes/CustomClassDefinitionTests.cs b/src/DotTiled.Tests/UnitTests/Properties/CustomTypes/CustomClassDefinitionTests.cs index 7e920e3..74e716c 100644 --- a/src/DotTiled.Tests/UnitTests/Properties/CustomTypes/CustomClassDefinitionTests.cs +++ b/src/DotTiled.Tests/UnitTests/Properties/CustomTypes/CustomClassDefinitionTests.cs @@ -70,11 +70,42 @@ public class CustomClassDefinitionTests ] }; + private enum TestEnum1 + { + Value1, + Value2 + } + + [Flags] + private enum TestFlags1 + { + Value1 = 0b001, + Value2 = 0b010, + Value3 = 0b100 + } + + private sealed class TestClass4WithEnums + { + public TestEnum1 Enum { get; set; } = TestEnum1.Value2; + public TestFlags1 Flags { get; set; } = TestFlags1.Value1 | TestFlags1.Value2; + } + + private static CustomClassDefinition ExpectedTestClass4WithEnumsDefinition => new CustomClassDefinition + { + Name = "TestClass4WithEnums", + UseAs = CustomClassUseAs.All, + Members = [ + new EnumProperty { Name = "Enum", PropertyType = "TestEnum1", Value = new HashSet { "Value2" } }, + new EnumProperty { Name = "Flags", PropertyType = "TestFlags1", Value = new HashSet { "Value1", "Value2" } } + ] + }; + private static IEnumerable<(Type, CustomClassDefinition)> GetCustomClassDefinitionTestData() { yield return (typeof(TestClass1), ExpectedTestClass1Definition); yield return (typeof(TestClass2WithNestedClass), ExpectedTestClass2WithNestedClassDefinition); yield return (typeof(TestClass3WithOverridenNestedClass), ExpectedTestClass3WithOverridenNestedClassDefinition); + yield return (typeof(TestClass4WithEnums), ExpectedTestClass4WithEnumsDefinition); } public static IEnumerable CustomClassDefinitionTestData => diff --git a/src/DotTiled/Properties/CustomTypes/CustomClassDefinition.cs b/src/DotTiled/Properties/CustomTypes/CustomClassDefinition.cs index b674f48..37b8c6e 100644 --- a/src/DotTiled/Properties/CustomTypes/CustomClassDefinition.cs +++ b/src/DotTiled/Properties/CustomTypes/CustomClassDefinition.cs @@ -166,19 +166,16 @@ public class CustomClassDefinition : HasPropertiesBase, ICustomTypeDefinition case Type t when t.IsClass: return new ClassProperty { Name = propertyInfo.Name, PropertyType = t.Name, Value = GetNestedProperties(propertyInfo.PropertyType, propertyInfo.GetValue(instance)) }; case Type t when t.IsEnum: - var isFlags = t.GetCustomAttributes(typeof(FlagsAttribute), false).Length != 0; + var enumDefinition = CustomEnumDefinition.FromEnum(t); - if (isFlags) - { - ISet values = new HashSet(); - foreach (var value in t.GetEnumValues()) - { - if (((int)value & (int)propertyInfo.GetValue(instance)) != 0) values.Add(t.GetEnumName(value)); - } - return new EnumProperty { Name = propertyInfo.Name, PropertyType = t.Name, Value = values }; - } + if (!enumDefinition.ValueAsFlags) + return new EnumProperty { Name = propertyInfo.Name, PropertyType = t.Name, Value = new HashSet { propertyInfo.GetValue(instance).ToString() } }; - return new EnumProperty { Name = propertyInfo.Name, PropertyType = t.Name, Value = new HashSet { t.GetEnumName(propertyInfo.GetValue(instance)) } }; + var flags = (Enum)propertyInfo.GetValue(instance); + var enumValues = Enum.GetValues(t).Cast(); + var enumNames = enumValues.Where(flags.HasFlag).Select(e => e.ToString()); + + return new EnumProperty { Name = propertyInfo.Name, PropertyType = t.Name, Value = enumNames.ToHashSet() }; default: break; }