From eb0f05ed6af0913562dd3c5be1415233f8b7f4e7 Mon Sep 17 00:00:00 2001 From: Michael Hancock Date: Tue, 7 Apr 2020 11:58:43 +0100 Subject: [PATCH] Add flag enum support Fixes #8 --- src/EnumDisplayName/EnumExtensions.cs | 80 ++++++++++++--- .../EnumExtensionsGetFlagsDisplayNameTests.cs | 99 +++++++++++++++++++ .../Enums/MockFlagEnum.cs | 25 +++++ 3 files changed, 193 insertions(+), 11 deletions(-) create mode 100644 test/EnumDisplayName.Test/EnumExtensionsGetFlagsDisplayNameTests.cs create mode 100644 test/EnumDisplayName.Test/Enums/MockFlagEnum.cs diff --git a/src/EnumDisplayName/EnumExtensions.cs b/src/EnumDisplayName/EnumExtensions.cs index 85d1f1f..443f4b5 100644 --- a/src/EnumDisplayName/EnumExtensions.cs +++ b/src/EnumDisplayName/EnumExtensions.cs @@ -1,9 +1,13 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; #if NETSTANDARD1_3 + using System.Reflection; + #endif namespace Enable.EnumDisplayName @@ -35,26 +39,80 @@ public static string GetDisplayName(this Enum enumValue) if (string.Compare(fieldName, field.Name, StringComparison.Ordinal) == 0) { - var customAttributes = field.GetCustomAttributes(false); - var enumDisplayNameAttribute = customAttributes.OfType().FirstOrDefault(); + var fieldAttributes = field.GetCustomAttributes(false).Cast(); + return GetNameFromEnumField(enumValue, fieldAttributes); + } + } - if (enumDisplayNameAttribute != null) - { - return enumDisplayNameAttribute.GetDisplayName(); - } + return string.Empty; + } + + /// + /// Returns the display names of a flag enum as a comma seperated string as specified by the + /// EnumDisplayNameAttribute declared on the enum field. If no EnumDisplayNameAttribute is + /// declared on the enum field then the name of the enum field is returned. + /// + public static string GetFlagsDisplayName(this Enum enumValue) + { + if (enumValue == null) + { + return string.Empty; + } - var displayNameAttribute = customAttributes.OfType().FirstOrDefault(); + var enumType = enumValue.GetType(); + var fieldNames = Enum.GetNames(enumType); + var fields = enumType.GetFields() + .Where(o => fieldNames.Any(p => p == o.Name)) + .ToArray(); - if (displayNameAttribute != null) + var fieldPosition = 0; + var result = string.Empty; + foreach (Enum currentValue in Enum.GetValues(enumType)) + { + if (enumValue.HasFlag(currentValue)) + { + var currentField = fields[fieldPosition]; + if (currentField.IsSpecialName) { - return displayNameAttribute.GetName(); + fieldPosition += 1; + continue; } - return fieldName; + var fieldAttributes = currentField + .GetCustomAttributes(false) + .Cast(); + + var fieldName = GetNameFromEnumField(enumValue, fieldAttributes); + + result = result == string.Empty ? fieldName + : result + "," + fieldName; } + + fieldPosition += 1; } - return string.Empty; + return result; + } + + private static string GetNameFromEnumField(Enum enumValue, IEnumerable fieldAttributes) + { + var enumType = enumValue.GetType(); + var fieldName = Enum.GetName(enumType, enumValue); + var enumDisplayNameAttribute = fieldAttributes.OfType().FirstOrDefault(); + + if (enumDisplayNameAttribute != null) + { + return enumDisplayNameAttribute.GetDisplayName(); + } + + var displayNameAttribute = fieldAttributes.OfType().FirstOrDefault(); + + if (displayNameAttribute != null) + { + return displayNameAttribute.GetName(); + } + + return fieldName; } } } diff --git a/test/EnumDisplayName.Test/EnumExtensionsGetFlagsDisplayNameTests.cs b/test/EnumDisplayName.Test/EnumExtensionsGetFlagsDisplayNameTests.cs new file mode 100644 index 0000000..16cc259 --- /dev/null +++ b/test/EnumDisplayName.Test/EnumExtensionsGetFlagsDisplayNameTests.cs @@ -0,0 +1,99 @@ +using System; +using Xunit; + +namespace Enable.EnumDisplayName +{ + public class EnumExtensionsGetFlagsDisplayNameTests + { + [Fact] + public void GetFlagsDisplayName_ReturnsEmptyStringWhenSourceIsNull() + { + // Arrange + Enum source = null; + + // Act + var result = source.GetFlagsDisplayName(); + + // Assert + Assert.Equal(string.Empty, result); + } + + [Fact] + public void GetFlagsDisplayName_ReturnsEnumDisplayNameAttributeDisplayName() + { + // Act + var result = MockFlagEnum.EnumDisplayNameAttribute.GetFlagsDisplayName(); + + // Assert + Assert.Equal(MockEnumDisplayNames.EnumDisplayNameAttribute, result); + } + + [Fact] + public void GetFlagsDisplayName_ReturnsEnumDisplayNameAttributeWithResourceDisplayName() + { + // Act + var result = MockFlagEnum.EnumDisplayNameAttributeWithResource.GetFlagsDisplayName(); + + // Assert + Assert.Equal(Resources.MockEnum.EnumDisplayNameAttributeWithResource, result); + } + + [Fact] + public void GetFlagsDisplayName_ReturnsDisplayAttributeDisplayName() + { + // Act + var result = MockFlagEnum.DisplayAttribute.GetFlagsDisplayName(); + + // Assert + Assert.Equal(MockEnumDisplayNames.DisplayAttribute, result); + } + + [Fact] + public void GetFlagsDisplayName_ReturnsFieldName() + { + // Act + var result = MockFlagEnum.NoAttribute.GetFlagsDisplayName(); + + // Assert + Assert.Equal(MockEnumDisplayNames.NoAttribute, result); + } + + [Fact] + public void GetFlagsDisplayName_ReturnsEmptyStringWithSpecialNameAttribute() + { + // Act + var result = MockFlagEnum.SpecialName.GetFlagsDisplayName(); + + // Assert + Assert.Equal(string.Empty, result); + } + + [Fact] + public void GetFlagsDisplayName_ReturnsCommaSeperatedStringForFlagValues() + { + // Arrange + var sut = MockFlagEnum.DisplayAttribute | MockFlagEnum.EnumDisplayNameAttribute; + + // Act + var result = sut.GetFlagsDisplayName(); + + // Assert + var expected = $"{MockEnumDisplayNames.EnumDisplayNameAttribute},{MockEnumDisplayNames.DisplayAttribute}"; + Assert.Equal(expected, result); + } + + [Fact] + public void GetFlagsDisplayName_ReturnsCommaSeperatedStringForFlagValues_ExceptSpecialNameAttributes() + { + // Arrange + var sut = MockFlagEnum.DisplayAttribute | MockFlagEnum.SpecialName; + + // Act + var result = sut.GetFlagsDisplayName(); + + // Assert + var expected = $"{MockEnumDisplayNames.DisplayAttribute}"; + Assert.Equal(expected, result); + } + } +} diff --git a/test/EnumDisplayName.Test/Enums/MockFlagEnum.cs b/test/EnumDisplayName.Test/Enums/MockFlagEnum.cs new file mode 100644 index 0000000..84d3656 --- /dev/null +++ b/test/EnumDisplayName.Test/Enums/MockFlagEnum.cs @@ -0,0 +1,25 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Runtime.CompilerServices; + +namespace Enable.EnumDisplayName +{ + [Flags] + public enum MockFlagEnum + { + [EnumDisplayName(MockEnumDisplayNames.EnumDisplayNameAttribute)] + EnumDisplayNameAttribute = 1, + + [EnumDisplayName(MockEnumDisplayNames.EnumDisplayNameAttributeWithResource, typeof(Resources.MockEnum))] + EnumDisplayNameAttributeWithResource = 2, + + [Display(Name = MockEnumDisplayNames.DisplayAttribute)] + DisplayAttribute = 4, + + NoAttribute = 8, + + [SpecialName] + [EnumDisplayName(MockEnumDisplayNames.SpecialName)] + SpecialName = 16 + } +}