/Utilities/Helpers/EnumHelper.cs
C# | 1135 lines | 687 code | 110 blank | 338 comment | 35 complexity | a9d723da4a25ba7ca879c28315c2a931 MD5 | raw file
Possible License(s): Apache-2.0
1using System; 2using System.Collections; 3using System.Collections.Generic; 4using System.ComponentModel; 5using System.Globalization; 6using System.Reflection; 7using NUnit.Framework; 8 9namespace Delta.Utilities.Helpers 10{ 11 /// <summary> 12 /// Enum helper class, allows extracting Description attributes, which is 13 /// useful for displaying name of enum and stuff. Also useful because 14 /// Descriptions don't get obfuscated and EnumHelper has extra operations, 15 /// like GetSize to get the number of elements an enum uses. 16 /// </summary> 17 public static class EnumHelper 18 { 19 #region EnumEnumerator Class 20 /// <summary> 21 /// Enum enumerator helper for GetEnumerator, 22 /// this allow us to enumerate enums just like collections 23 /// </summary> 24 public class EnumEnumerator 25 : IEnumerator, IEnumerable 26 { 27 #region EnumType (Public) 28 /// <summary> 29 /// The enum we use 30 /// </summary> 31 public Type EnumType; 32 #endregion 33 34 #region index (Public) 35 /// <summary> 36 /// Own index 37 /// </summary> 38 public int index; 39 #endregion 40 41 #region EnumCount (Public) 42 /// <summary> 43 /// Count of enum values. 44 /// </summary> 45 /// <returns>Int</returns> 46 public int EnumCount 47 { 48 get 49 { 50 return enumValues.Length; 51 } 52 } 53 #endregion 54 55 #region Current (Public) 56 /// <summary> 57 /// Current enum value 58 /// </summary> 59 public object Current 60 { 61 get 62 { 63 if (index >= 0 && 64 index < EnumCount) 65 { 66 return enumValues.GetValue(index); 67 } 68 else 69 { 70 // Just return first entry if index is invalid 71 return enumValues.GetValue(0); 72 } 73 } 74 } 75 #endregion 76 77 #region Private 78 79 #region enumValues (Private) 80 /// <summary> 81 /// Enum values 82 /// </summary> 83 private readonly Array enumValues; 84 #endregion 85 86 #endregion 87 88 #region Constructors 89 /// <summary> 90 /// Create enum enumerator 91 /// </summary> 92 /// <param name="setEnumType">Enum type</param> 93 public EnumEnumerator(Type setEnumType) 94 { 95 EnumType = setEnumType; 96 index = -1; 97 enumValues = Enum.GetValues(EnumType); 98 } 99 #endregion 100 101 #region IEnumerable Members 102 /// <summary> 103 /// Get enumerator 104 /// </summary> 105 /// <returns>Enumerator to enumerate with</returns> 106 public IEnumerator GetEnumerator() 107 { 108 return this; 109 } 110 #endregion 111 112 #region IEnumerator Members 113 /// <summary> 114 /// Move next 115 /// </summary> 116 public bool MoveNext() 117 { 118 index++; 119 // Finished? 120 return index < EnumCount; 121 } 122 123 /// <summary> 124 /// Reset 125 /// </summary> 126 public void Reset() 127 { 128 index = -1; 129 } 130 #endregion 131 } 132 #endregion 133 134 #region GetCount (Static) 135 /// <summary> 136 /// Gets the number of elements for the given Enum type. 137 /// </summary> 138 /// <typeparam name="T">Type of enum</typeparam> 139 /// <returns>Number of possible enum elements</returns> 140 public static int GetCount<T>() 141 { 142 Type enumType = typeof(T); 143 if (enumType.IsEnum) 144 { 145 return Enum.GetValues(enumType).Length; 146 } 147 148 Log.Warning( 149 "EnumHelper.GetCount: The given type=" + enumType + " isn't a " + 150 "valid enum!"); 151 return 0; 152 } 153 154 /// <summary> 155 /// Gets the number of elements for the given Enum type. 156 /// </summary> 157 /// <param name="anyEnum">Any enum value</param> 158 /// <returns>Number of enum values in this given enum</returns> 159 public static int GetCount(this Enum anyEnum) 160 { 161 Type enumType = anyEnum.GetType(); 162 if (enumType.IsEnum) 163 { 164 return Enum.GetValues(enumType).Length; 165 } 166 167 Log.Warning( 168 "EnumHelper.GetCount: The given type=" + enumType + " isn't a valid " + 169 "enum!"); 170 return 0; 171 } 172 #endregion 173 174 #region NextValue (Static) 175 /// <summary> 176 /// Get the next enum value in any given enum. 177 /// </summary> 178 /// <typeparam name="T">Type for this enum</typeparam> 179 /// <param name="enumValue">Enum type</param> 180 /// <returns>Next enum value</returns> 181 public static T NextValue<T>(this T enumValue) 182 where T : IConvertible 183 { 184 // At first we determine the type 185 Type enumType = typeof(T); 186 // to look if the given object is really an Enum 187 if (enumType.IsEnum == false) 188 { 189 // if not, we log a warning 190 Log.Warning( 191 "EnumHelper.NextValue: The given type=" + enumType + " isn't a " + 192 "valid enum!"); 193 // and just return the given value back... 194 return enumValue; 195 } 196 197 // To know which is the current value of the enum, we just iterate 198 // through all of them (in worst case) 199 Array enumValues = Enum.GetValues(enumType); 200 int foundIndex = MathHelper.InvalidIndex; 201 for (int i = 0; i < enumValues.Length; i++) 202 { 203 // If we have found it (which occurs every time sooner or later) 204 if (enumValues.GetValue(i).Equals(enumValue)) 205 { 206 // we "compute" the index of the next value, which is just the next 207 // index or the first index, if the current value is the last one 208 // -> cycling 209 foundIndex = 210 i == enumValues.Length - 1 211 ? 0 212 : i + 1; 213 break; 214 } 215 } 216 217 return (T)enumValues.GetValue(foundIndex); 218 } 219 #endregion 220 221 #region ToUInt64 (Static) 222 /// <summary> 223 /// Converts given enum into unsigned long 224 /// </summary> 225 /// <param name="enumValue">Enum value to convert</param> 226 /// <returns>Unsigned long value created from this enum value</returns> 227 /// <exception cref="InvalidOperationException"> 228 /// Invalid internal enum type 229 /// </exception> 230 public static ulong ToUInt64(this Enum enumValue) 231 { 232 switch (enumValue.GetTypeCode()) 233 { 234 case TypeCode.SByte: 235 case TypeCode.Int16: 236 case TypeCode.Int32: 237 case TypeCode.Int64: 238 return (ulong)Convert.ToInt64(enumValue, 239 CultureInfo.InvariantCulture); 240 241 case TypeCode.Byte: 242 case TypeCode.UInt16: 243 case TypeCode.UInt32: 244 case TypeCode.UInt64: 245 return Convert.ToUInt64(enumValue, CultureInfo.InvariantCulture); 246 } 247 248 throw new InvalidOperationException("Invalid internal enum type"); 249 } 250 #endregion 251 252 #region ToInt (Static) 253 /// <summary> 254 /// Converts given enum into int 255 /// </summary> 256 /// <param name="enumValue">Enum value to convert</param> 257 /// <returns>Integer value created from this enum value</returns> 258 /// <exception cref="InvalidOperationException"></exception> 259 public static int ToInt(this Enum enumValue) 260 { 261 TypeCode typeCode = enumValue.GetTypeCode(); 262 switch (typeCode) 263 { 264 case TypeCode.SByte: 265 case TypeCode.Int16: 266 case TypeCode.Int32: 267 case TypeCode.Byte: 268 case TypeCode.UInt16: 269 return Convert.ToInt32(enumValue, CultureInfo.InvariantCulture); 270 271 case TypeCode.UInt32: 272 case TypeCode.Int64: 273 case TypeCode.UInt64: 274 Log.Warning( 275 "You are converting an enum with internal type of " + typeCode + 276 " to an Int32. This may yield wrong results, so use ToUInt64 " + 277 "instead."); 278 return Convert.ToInt32(enumValue, CultureInfo.InvariantCulture); 279 } 280 281 throw new InvalidOperationException( 282 "Invalid internal enum type: " + typeCode); 283 } 284 #endregion 285 286 #region IsFlagSet (Static) 287 /// <summary> 288 /// Checks if given Enum has given flag set. If the enum does not use 289 /// flags, this method should not be used. 290 /// </summary> 291 /// <param name="combinedEnum">Combined enum value</param> 292 /// <param name="flag">Flag to check</param> 293 /// <returns>True if the enum flag is set, false otherwise.</returns> 294 public static bool IsFlagSet(this Enum combinedEnum, Enum flag) 295 { 296 return combinedEnum.HasFlag(flag); 297 } 298 #endregion 299 300 #region ToEnum (Static) 301 /// <summary> 302 /// Simple implementation which replaces all other Enum conversion methods. 303 /// Works with: String names, string numbers, Combined enums (comma 304 /// separated, or as number string), Irregular numbered ones. 305 /// It returns default enum value, if there is no match. 306 /// </summary> 307 /// <typeparam name="T">Type of enum to parse</typeparam> 308 /// <param name="enumName"> 309 /// Enum string to convert (can be a number, a string, a comma separated 310 /// combination or a combined number) 311 /// </param> 312 /// <returns> 313 /// Enum type parsed or the default value if parsing was not possible 314 /// </returns> 315 public static T ToEnum<T>(this string enumName) 316 { 317 try 318 { 319 return 320 String.IsNullOrEmpty(enumName) 321 ? default(T) 322 : (T)Enum.Parse(typeof(T), enumName, false); 323 } 324 catch (Exception) 325 { 326 return default(T); 327 } 328 } 329 330 /// <summary> 331 /// Simple implementation which replaces all other Enum conversion methods. 332 /// Works with: String names, string numbers, Combined enums (comma 333 /// separated, or as number string), Irregular numbered ones. 334 /// It returns default enum value, if there is no match. 335 /// </summary> 336 /// <typeparam name="T">Type of enum to parse</typeparam> 337 /// <param name="enumNames"> 338 /// Enum string array of enum values, which will be combined into one 339 /// comma separated string and converted to an Enum. 340 /// </param> 341 /// <returns> 342 /// Enum type parsed or the default value if parsing was not possible 343 /// </returns> 344 public static T ToEnum<T>(this string[] enumNames) 345 { 346 return enumNames.Write().ToEnum<T>(); 347 } 348 349 /// <summary> 350 /// Simple implementation which replaces all other Enum conversion methods. 351 /// Works with: String names, string numbers, Combined enums (comma 352 /// separated, or as number string), Irregular numbered ones. 353 /// It returns default enum value, if there is no match. 354 /// </summary> 355 /// <typeparam name="T">Type of enum to parse</typeparam> 356 /// <param name="enumName"> 357 /// Enum string to convert (can be a number, a string, a comma separated 358 /// combination or a combined number) 359 /// </param> 360 /// <param name="result"> 361 /// Enum type parsed or the default value if parsing was not possible 362 /// </param> 363 /// <returns>True if the enum value was found, false otherwise</returns> 364 public static bool ToEnum<T>(this string enumName, out T result) 365 { 366 if (String.IsNullOrEmpty(enumName)) 367 { 368 // Special case: treat empty string as default value 369 result = default(T); 370 return true; 371 } 372 try 373 { 374 result = (T)Enum.Parse(typeof(T), enumName, false); 375 return true; 376 } 377 catch (Exception) 378 { 379 result = default(T); 380 return false; 381 } 382 } 383 #endregion 384 385 #region GetEnumIndex (Static) 386 /// <summary> 387 /// Get enum index from value. If we use a known enum, we could simply 388 /// write (int)SomeEnum.Value, but we can't do that with System.Enum 389 /// we have to use in a lot of methods or if we use an auto-generated enum 390 /// </summary> 391 /// <param name="enumValue">Enum value</param> 392 /// <returns> 393 /// Index of the enum value, which is normally the enum value, 394 /// but if the enum uses custom values for each enum, it is not the same! 395 /// </returns> 396 public static int GetEnumIndex(this Enum enumValue) 397 { 398 string[] enumNames = Enum.GetNames(enumValue.GetType()); 399 400 for (int num = 0; num < enumNames.Length; num++) 401 { 402 if (enumValue.ToString() == enumNames[num]) 403 { 404 return num; 405 } 406 } 407 408 // If not found, just return maxValue + 1. Don't throw any exception 409 return enumNames.Length; 410 } 411 #endregion 412 413 #region SelectNextEnum (Static) 414 /// <summary> 415 /// Select next enum 416 /// </summary> 417 /// <param name="enumValue">Enum</param> 418 /// <returns>Next enum value</returns> 419 public static Enum SelectNextEnum(this Enum enumValue) 420 { 421 Array enumValues = Enum.GetValues(enumValue.GetType()); 422 423 // Select next enum value 424 int valueIndex = (GetEnumIndex(enumValue) + 1) % GetCount(enumValue); 425 return (Enum)enumValues.GetValue(valueIndex); 426 } 427 #endregion 428 429 #region Next (Static) 430 /// <summary> 431 /// Get next enum value 432 /// </summary> 433 /// <param name="enumValue">Enum</param> 434 /// <returns>Next enum value</returns> 435 public static Enum Next(this Enum enumValue) 436 { 437 return SelectNextEnum(enumValue); 438 } 439 #endregion 440 441 #region SelectPreviousEnum (Static) 442 /// <summary> 443 /// Select previous enum 444 /// </summary> 445 /// <param name="enumValue">Enum</param> 446 /// <returns>Previous enum value</returns> 447 public static Enum SelectPreviousEnum(this Enum enumValue) 448 { 449 Array enumValues = Enum.GetValues(enumValue.GetType()); 450 451 // Select next enum value 452 int valueIndex = (GetEnumIndex(enumValue) - 1) % GetCount(enumValue); 453 if (valueIndex < 0) 454 { 455 valueIndex += GetCount(enumValue); 456 } 457 return (Enum)enumValues.GetValue(valueIndex); 458 } 459 #endregion 460 461 #region Previous (Static) 462 /// <summary> 463 /// Get previous enum value 464 /// </summary> 465 /// <param name="enumValue">Enum</param> 466 /// <returns>Previous enum value</returns> 467 public static Enum Previous(this Enum enumValue) 468 { 469 return SelectPreviousEnum(enumValue); 470 } 471 #endregion 472 473 #region GetValues (Static) 474 /// <summary> 475 /// Returns all values of the given enum, which is severy single possible 476 /// enum value as an array of enum values. For more details see: 477 /// http://www.dolittle.no/blogs/einar/archive/2008/01/13/missing-enum-getvalues-when-doing-silverlight-for-instance.aspx 478 /// </summary> 479 public static T[] GetValues<T>() 480 { 481 Type enumType = typeof(T); 482 483 #region Validation 484 if (enumType.IsEnum == false) 485 { 486 Log.Warning("The given type '" + enumType + "' isn't an enum"); 487 return new T[0]; 488 } 489 #endregion 490 491 List<T> values = new List<T>(); 492 foreach (FieldInfo field in enumType.GetFields()) 493 { 494 if (field.IsLiteral) 495 { 496 T value = (T)field.GetValue(enumType); 497 values.Add(value); 498 } 499 } 500 501 return values.ToArray(); 502 } 503 504 /// <summary> 505 /// Returns all values of the given enum, which is severy single possible 506 /// enum value as an array of enum values. For more details see: 507 /// http://www.dolittle.no/blogs/einar/archive/2008/01/13/missing-enum-getvalues-when-doing-silverlight-for-instance.aspx 508 /// </summary> 509 /// <param name="enumType">Some enum type</param> 510 /// <returns>Array of enum values</returns> 511 public static Enum[] GetValues(this Type enumType) 512 { 513 #region Validation 514 if (enumType.IsEnum == false) 515 { 516 Log.Warning("The given type '" + enumType + "' isn't an enum"); 517 return new Enum[0]; 518 } 519 #endregion 520 521 List<Enum> values = new List<Enum>(); 522 foreach (FieldInfo field in enumType.GetFields()) 523 { 524 if (field.IsLiteral) 525 { 526 object value = field.GetValue(enumType); 527 values.Add((Enum)value); 528 } 529 } 530 531 return values.ToArray(); 532 } 533 #endregion 534 535 #region GetNames (Static) 536 /// <summary> 537 /// Returns the names for all enum values, which is severy single possible 538 /// enum value as a string array. For more details see: 539 /// http://stackoverflow.com/questions/1038234/iterating-through-an-enumeration-in-silverlight 540 /// </summary> 541 /// <typeparam name="T">Type of enum</typeparam> 542 /// <returns>List of strings with the enum names</returns> 543 public static string[] GetNames<T>() 544 { 545 return GetNames(typeof(T)); 546 } 547 548 /// <summary> 549 /// Returns the names for all enum values, which is severy single possible 550 /// enum value as a string array. For more details see: 551 /// http://stackoverflow.com/questions/1038234/iterating-through-an-enumeration-in-silverlight 552 /// </summary> 553 /// <param name="enumType">Some enum type</param> 554 /// <returns>List of strings with the enum names</returns> 555 public static string[] GetNames(Type enumType) 556 { 557 #region Validation 558 if (enumType.IsEnum == false) 559 { 560 Log.Warning("The given type '" + enumType + "' isn't an enum"); 561 return new string[0]; 562 } 563 #endregion 564 565 List<string> values = new List<string>(); 566 foreach (FieldInfo field in enumType.GetFields()) 567 { 568 if (field.IsLiteral) 569 { 570 values.Add(field.Name); 571 } 572 } 573 574 return values.ToArray(); 575 } 576 #endregion 577 578 #region GetEnumerator (Static) 579 /// <summary> 580 /// Get enumerator 581 /// </summary> 582 /// <returns>Enumerator for enumeration (foreach, etc.)</returns> 583 public static EnumEnumerator GetEnumerator(Type enumType) 584 { 585 return new EnumEnumerator(enumType); 586 } 587 #endregion 588 589 #region GetEnumDescription (Static) 590 /// <summary> 591 /// Gets enum value Description Attribute 592 /// </summary> 593 /// <param name="value"> 594 /// The value you want the description attribute for 595 /// </param> 596 /// <returns>The description, if any, else it's value.ToString()</returns> 597 public static string GetEnumDescription(this Enum value) 598 { 599 FieldInfo field = value.GetType().GetField(value.ToString()); 600 if (field != null) 601 { 602 DescriptionAttribute[] attributes = 603 (DescriptionAttribute[])field.GetCustomAttributes( 604 typeof(DescriptionAttribute), false); 605 return 606 attributes.Length > 0 607 ? attributes[0].Description 608 : value.ToString(); 609 } 610 611 // If that fails, just use enum name 612 return value.ToString(); 613 } 614 #endregion 615 616 #region Description (Static) 617 /// <summary> 618 /// Helper method to get an enum description attribute from a specific enum 619 /// value as a string. 620 /// </summary> 621 /// <param name="value">Enum value</param> 622 /// <returns> 623 /// Description text if available, otherwise just the enum name. 624 /// </returns> 625 public static string Description(this Enum value) 626 { 627 return GetEnumDescription(value); 628 } 629 #endregion 630 631 #region GetEnumDescription (Static) 632 /// <summary> 633 /// Gets the description for a certain named value in an enum 634 /// </summary> 635 /// <param name="value">The type of the enum</param> 636 /// <param name="name">The name of the enum value</param> 637 /// <returns>The description, if any, else the passed name</returns> 638 public static string GetEnumDescription(Type value, string name) 639 { 640 FieldInfo fi = value.GetField(name); 641 if (fi != null) 642 { 643 DescriptionAttribute[] attributes = 644 (DescriptionAttribute[])fi.GetCustomAttributes( 645 typeof(DescriptionAttribute), false); 646 return attributes.Length > 0 647 ? attributes[0].Description 648 : name; 649 } 650 // If that fails, just use name 651 return name; 652 } 653 #endregion 654 655 #region GetAllEnumDescriptions (Static) 656 /// <summary> 657 /// Get all enum descriptions as string array, useful for 658 /// Controls.DrawDropDownList(...) 659 /// </summary> 660 public static string[] GetAllEnumDescriptions(Type enumType) 661 { 662 ; 663 EnumEnumerator enumerator = GetEnumerator(enumType); 664 string[] descArray = new string[enumerator.EnumCount]; 665 666 foreach (Enum enumValue in enumerator) 667 { 668 descArray[enumerator.index] = 669 GetEnumDescription(enumValue); 670 } 671 672 return descArray; 673 } 674 675 /// <summary> 676 /// Get all enum descriptions as string array, useful for 677 /// Controls.DrawDropDownList(...) 678 /// </summary> 679 /// <param name="value">Enum value</param> 680 /// <returns>List of enum descriptions (if there are any)</returns> 681 public static string[] GetAllEnumDescriptions(this Enum value) 682 { 683 return GetAllEnumDescriptions(value.GetType()); 684 } 685 #endregion 686 687 #region GetEnumValue (Static) 688 /// <summary> 689 /// Gets the value of an enum, based on its Description Attribute or 690 /// named value. 691 /// </summary> 692 /// <param name="value">The enum type</param> 693 /// <param name="description">The description or name of the element 694 /// </param> 695 /// <returns>The value, or the passed in description, if it was not found 696 /// </returns> 697 public static object GetEnumValue(Type value, string description) 698 { 699 FieldInfo[] fis = value.GetFields(); 700 foreach (FieldInfo fi in fis) 701 { 702 DescriptionAttribute[] attributes = 703 (DescriptionAttribute[])fi.GetCustomAttributes( 704 typeof(DescriptionAttribute), false); 705 706 if ((attributes.Length > 0 && 707 attributes[0].Description == description) || 708 fi.Name == description) 709 { 710 return fi.GetValue(fi.Name); 711 } 712 } 713 714 return description; 715 } 716 #endregion 717 718 #region ToStringArray 719 /// <summary> 720 /// Get the combined enum values back as a string array. Makes only sense 721 /// for combined enums as normal enums will just return one entry and you 722 /// could just use ToString to get to that. 723 /// </summary> 724 /// <param name="value">Combined enum value</param> 725 /// <returns> 726 /// String array with all the selected enum values as names. You can use 727 /// ToEnum to convert the string array back to a combined enum. 728 /// </returns> 729 public static string[] ToStringArray(this Enum value) 730 { 731 return value.ToString().SplitAndTrim(','); 732 } 733 #endregion 734 735 #region SplitCombinedEnum 736 /// <summary> 737 /// Get the combined enum values back as an enum list. Makes only sense 738 /// for combined enums as normal enums will just return one entry and you 739 /// could just use the value itself. 740 /// </summary> 741 /// <param name="value">Combined enum value</param> 742 /// <returns> 743 /// List with all the selected enum values (flags) that were used to build 744 /// this combined enum. 745 /// </returns> 746 public static List<T> SplitCombinedEnum<T>(this T value) 747 where T : IConvertible 748 { 749 // Make sure we got a valid enum 750 if (value is Enum == false) 751 { 752 Log.Warning( 753 "EnumHelper.SplitCombinedEnum: The given type=" + value + " isn't " + 754 "a enum, unable to split it!"); 755 // And just return the given value back... 756 return new List<T>(new T[] 757 { 758 value 759 }); 760 } 761 762 string[] enumTexts = (value as Enum).ToStringArray(); 763 List<T> ret = new List<T>(); 764 if (enumTexts.Length > 1) 765 { 766 foreach (string enumText in enumTexts) 767 { 768 ret.Add(EnumHelper.ToEnum<T>(enumText)); 769 } 770 return ret; 771 } 772 773 // No combined enum, just return the current value 774 ret.Add(value); 775 return ret; 776 } 777 #endregion 778 779 /// <summary> 780 /// Enum helper tests 781 /// </summary> 782 public class EnumHelperTests 783 { 784 #region Helpers 785 /// <summary> 786 /// Test enum 787 /// </summary> 788 private enum TestEnum 789 { 790 [Description("Some entry")] 791 SomeEntry, 792 793 [Description("Another one")] 794 AnotherOne, 795 796 [Description("Hey stop it now")] 797 HeyStopItNow, 798 799 [Description("Okay okay")] 800 OkayOkay, 801 } 802 #endregion 803 804 #region Helpers 805 /// <summary> 806 /// Flag enum 807 /// </summary> 808 [Flags] 809 private enum FlagEnum : ulong 810 { 811 Flag1 = 1, 812 813 Flag2 = 2, 814 815 Flag3 = 4, 816 817 Flag4 = 8, 818 819 FlagUint64 = 1 << 48, 820 } 821 #endregion 822 823 #region Helpers 824 /// <summary> 825 /// Test combined enum 826 /// </summary> 827 [Flags] 828 private enum TestCombinedEnum 829 { 830 Zero = 0, 831 832 NumberOne = 1, 833 834 NumberTwo = 2, 835 836 NumberFour = 4, 837 } 838 #endregion 839 840 #region TestEnumStuff (Static) 841 /// <summary> 842 /// Test enum stuff. Note: Too slow for a dynamic unit test. 843 /// </summary> 844 [Test] 845 public static void TestEnumStuff() 846 { 847 //// First get size of TestEnum (with type of enum) 848 //Assert.Equal(GetSize(typeof(TestEnum)), 4); 849 //Assert.Equal(typeof(TestEnum).GetSize(), 4); 850 851 //// Now try with some enum member (should give the same result) 852 //Assert.Equal(GetSize(TestEnum.SomeEntry), 4); 853 854 // Test with extension 855 Assert.Equal(TestEnum.SomeEntry.GetCount(), 4); 856 Assert.Equal(TestEnum.SomeEntry.GetCount(), 4); 857 858 // Try to get enum from name 859 Assert.Equal(TestEnum.OkayOkay, 860 "OkayOkay".ToEnum<TestEnum>()); 861 862 // Get description of an enum members 863 Assert.Equal(GetEnumDescription(TestEnum.OkayOkay), "Okay okay"); 864 Assert.Equal(TestEnum.OkayOkay.Description(), "Okay okay"); 865 866 // Test enum enumerator stuff 867 string allEnumNames = GetEnumerator(typeof(TestEnum)).Write(); 868 Assert.Equal("SomeEntry, AnotherOne, HeyStopItNow, OkayOkay", 869 allEnumNames); 870 871 // Test same with description values 872 string allEnumDescNames = ""; 873 foreach (TestEnum enumValue in 874 GetEnumerator(typeof(TestEnum))) 875 { 876 allEnumDescNames += (allEnumDescNames.Length == 0 877 ? "" 878 : ", ") + 879 GetEnumDescription(enumValue); 880 } 881 Assert.Equal( 882 "Some entry, Another one, Hey stop it now, Okay okay", 883 allEnumDescNames); 884 885 // Same check with GetAllEnumDescriptions 886 Assert.Equal( 887 "Some entry, Another one, Hey stop it now, Okay okay", 888 GetAllEnumDescriptions(typeof(TestEnum)).Write()); 889 } 890 #endregion 891 892 #region TestNextAndPreviousEnum (Static) 893 /// <summary> 894 /// Test next and previous enum. Note: Too slow for a dynamic unit test. 895 /// </summary> 896 [Test] 897 public static void TestNextAndPreviousEnum() 898 { 899 TestEnum someEnum = TestEnum.SomeEntry; 900 Assert.Equal(TestEnum.SomeEntry, someEnum); 901 902 // Check next entry 903 someEnum = (TestEnum)someEnum.SelectNextEnum(); 904 Assert.Equal(TestEnum.AnotherOne, someEnum); 905 Assert.Equal(TestEnum.AnotherOne, TestEnum.SomeEntry.Next()); 906 907 // Go back 2 entries, this will select the last enum entry 908 someEnum = (TestEnum)someEnum.SelectPreviousEnum(); 909 someEnum = (TestEnum)someEnum.SelectPreviousEnum(); 910 Assert.Equal(TestEnum.OkayOkay, someEnum); 911 Assert.Equal(TestEnum.AnotherOne, TestEnum.HeyStopItNow.Previous()); 912 } 913 #endregion 914 915 #region TestGetAllEnumValues (Static) 916 /// <summary> 917 /// Test get all enum values. Note: Too slow for a dynamic unit test. 918 /// </summary> 919 [Test] 920 public static void TestGetAllEnumValues() 921 { 922 // Test with type 923 TestEnum[] enums = GetValues<TestEnum>(); 924 Assert.Equal("SomeEntry, AnotherOne, HeyStopItNow, OkayOkay", 925 enums.Write()); 926 927 // Create with instance 928 string[] inputEnumNames = new[] 929 { 930 "SomeEntry", 931 "AnotherOne", 932 "HeyStopItNow", 933 "OkayOkay", 934 }; 935 936 //This code needs reflection, not supported right now in DE: 937 //enums = GetAllEnumValues(CreateEnum(inputEnumNames).GetType()); 938 //Assert.Equal("SomeEntry, AnotherOne, HeyStopItNow, OkayOkay", 939 // ArrayHelper.Write(enums)); 940 } 941 #endregion 942 943 #region GetValues (Static) 944 /// <summary> 945 /// Get values 946 /// </summary> 947 [Test] 948 public static void GetValues() 949 { 950 object[] values = typeof(StringSplitOptions).GetValues(); 951 Assert.Equal(values.Length, 2); 952 Assert.Equal(values[0], StringSplitOptions.None); 953 Assert.Equal(values[1], StringSplitOptions.RemoveEmptyEntries); 954 955 StringSplitOptions[] genericValues = 956 GetValues<StringSplitOptions>(); 957 Assert.Equal(genericValues.Length, 2); 958 Assert.Equal(genericValues[0], StringSplitOptions.None); 959 Assert.Equal(genericValues[1], StringSplitOptions.RemoveEmptyEntries); 960 } 961 #endregion 962 963 #region GetNames (Static) 964 /// <summary> 965 /// Get names 966 /// </summary> 967 [Test] 968 public static void GetNames() 969 { 970 string[] names = EnumHelper.GetNames(typeof(StringSplitOptions)); 971 Assert.Equal(names.Length, 2); 972 Assert.Equal(names[0], "None"); 973 Assert.Equal(names[1], "RemoveEmptyEntries"); 974 975 string[] genericNames = GetNames<StringSplitOptions>(); 976 Assert.Equal(genericNames.Length, 2); 977 Assert.Equal(genericNames[0], "None"); 978 Assert.Equal(genericNames[1], "RemoveEmptyEntries"); 979 } 980 #endregion 981 982 #region ConvertToNumberWithCombinedEnum (LongRunning) 983 /// <summary> 984 /// Convert to number 985 /// </summary> 986 [Test] 987 public void ConvertToNumberWithCombinedEnum() 988 { 989 // Reproduce test with standard methods 990 Assert.Equal(4, (int)"NumberFour".ToEnum<TestCombinedEnum>()); 991 Assert.Equal(6, 992 (int)"NumberTwo, NumberFour".ToEnum<TestCombinedEnum>()); 993 Assert.Equal( 994 (int)(TestCombinedEnum.NumberTwo | TestCombinedEnum.NumberFour), 995 (int)"6".ToEnum<TestCombinedEnum>()); 996 Assert.Equal("NumberTwo, NumberFour", 997 (TestCombinedEnum.NumberTwo | 998 TestCombinedEnum.NumberFour).ToString()); 999 Assert.Equal(TestCombinedEnum.Zero, "bla".ToEnum<TestCombinedEnum>()); 1000 Assert.Equal("Zero", TestCombinedEnum.Zero.ToString()); 1001 1002 Assert.Equal(0, 1003 (int)(TestCombinedEnum.Zero.ToString(). 1004 ToEnum<TestCombinedEnum>())); 1005 Assert.Equal( 1006 (int)(TestCombinedEnum.NumberTwo | 1007 TestCombinedEnum.NumberFour), 1008 (int)(TestCombinedEnum.NumberTwo | 1009 TestCombinedEnum.NumberFour.ToString(). 1010 ToEnum<TestCombinedEnum>())); 1011 1012 // Finally write down a combined enum. 1013 TestCombinedEnum combinedValue = 1014 TestCombinedEnum.NumberTwo | 1015 TestCombinedEnum.NumberFour; 1016 Assert.Equal("NumberTwo, NumberFour", combinedValue.ToString()); 1017 Assert.Equal(combinedValue.ToStringArray(), new string[] 1018 { 1019 "NumberTwo", "NumberFour" 1020 }); 1021 // This can be useful to build a combined enum name as a filename! 1022 Assert.Equal(combinedValue.ToStringArray().Write("_"), 1023 "NumberTwo_NumberFour"); 1024 Assert.Equal(combinedValue, 1025 combinedValue.ToStringArray().ToEnum<TestCombinedEnum>()); 1026 } 1027 #endregion 1028 1029 #region GetCount 1030 /// <summary> 1031 /// Get count 1032 /// </summary> 1033 [Test] 1034 public void GetCount() 1035 { 1036 Assert.Equal(7, GetCount<DayOfWeek>()); 1037 } 1038 #endregion 1039 1040 #region NextValue 1041 /// <summary> 1042 /// Next value 1043 /// </summary> 1044 [Test] 1045 public void NextValue() 1046 { 1047 Assert.Equal(DayOfWeek.Monday, DayOfWeek.Sunday.NextValue()); 1048 } 1049 #endregion 1050 1051 #region ToEnum 1052 /// <summary> 1053 /// Get enum from name 1054 /// </summary> 1055 [Test] 1056 public void ToEnum() 1057 { 1058 // Standard Enum 1059 Assert.Equal(FlagEnum.Flag2, "Flag2".ToEnum<FlagEnum>()); 1060 1061 // Combined Enum 1062 Assert.Equal(FlagEnum.Flag1 | FlagEnum.Flag3, 1063 "Flag1, Flag3".ToEnum<FlagEnum>()); 1064 Assert.Equal(FlagEnum.Flag2 | FlagEnum.Flag4, 1065 "Flag4, Flag2".ToEnum<FlagEnum>()); 1066 1067 // Number to Enum 1068 Assert.Equal(FlagEnum.Flag3, 1069 "4".ToEnum<FlagEnum>()); 1070 1071 // Number to combined Enum 1072 Assert.Equal(FlagEnum.Flag2 | FlagEnum.Flag4, 1073 "10".ToEnum<FlagEnum>()); 1074 } 1075 #endregion 1076 1077 #region FlagTests 1078 /// <summary> 1079 /// Flag tests 1080 /// </summary> 1081 [Test] 1082 public void FlagTests() 1083 { 1084 Assert.Equal(2, 1085 (int)("NumberTwo, NumberFour".ToEnum<TestCombinedEnum>() & 1086 TestCombinedEnum.NumberTwo)); 1087 } 1088 #endregion 1089 1090 #region ConvertToInteger 1091 /// <summary> 1092 /// ConvertToInteger test 1093 /// </summary> 1094 [Test] 1095 public void ConvertToInteger() 1096 { 1097 // Test with int 1098 Assert.Equal(2, TestCombinedEnum.NumberTwo.ToInt()); 1099 Assert.Equal(6, 1100 (TestCombinedEnum.NumberFour | 1101 TestCombinedEnum.NumberTwo).ToInt()); 1102 1103 // Test with UInt64 1104 Assert.Equal<ulong>(1 << 48, FlagEnum.FlagUint64.ToUInt64()); 1105 1106 // This should warn about possible overflows 1107 Assert.Equal(4, FlagEnum.Flag3.ToInt()); 1108 } 1109 #endregion 1110 1111 #region ToInt 1112 /// <summary> 1113 /// Convert to number 1114 /// </summary> 1115 [Test] 1116 public void ToInt() 1117 { 1118 Assert.Equal(0, 1119 EnumHelper.ToInt(TestCombinedEnum.Zero)); 1120 Assert.Equal(2, 1121 EnumHelper.ToInt(TestCombinedEnum.NumberTwo)); 1122 1123 Assert.Equal(4, 1124 EnumHelper.ToInt(TestCombinedEnum.NumberFour)); 1125 Assert.Equal(6, EnumHelper.ToInt( 1126 TestCombinedEnum.NumberTwo | TestCombinedEnum.NumberFour)); 1127 Assert.Equal(TestCombinedEnum.NumberFour, 1128 EnumHelper.ToEnum<TestCombinedEnum>("4")); 1129 Assert.Equal(TestCombinedEnum.NumberTwo | TestCombinedEnum.NumberFour, 1130 EnumHelper.ToEnum<TestCombinedEnum>("6")); 1131 } 1132 #endregion 1133 } 1134 } 1135}