AutoInitShutdownAttribute.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. using System.Diagnostics;
  2. using System.Globalization;
  3. using System.Reflection;
  4. using Xunit.Sdk;
  5. namespace UnitTests;
  6. /// <summary>
  7. /// Enables test functions annotated with the [AutoInitShutdown] attribute to
  8. /// automatically call Application.Init at start of the test and Application.Shutdown after the
  9. /// test exits.
  10. /// This is necessary because a) Application is a singleton and Init/Shutdown must be called
  11. /// as a pair, and b) all unit test functions should be atomic..
  12. /// </summary>
  13. [AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]
  14. public class AutoInitShutdownAttribute : BeforeAfterTestAttribute
  15. {
  16. /// <summary>
  17. /// Initializes a [AutoInitShutdown] attribute, which determines if/how Application.Init and Application.Shutdown
  18. /// are automatically called Before/After a test runs.
  19. /// </summary>
  20. /// <param name="autoInit">If true, Application.Init will be called Before the test runs.</param>
  21. /// <param name="consoleDriverType">
  22. /// Determines which IConsoleDriver (FakeDriver, WindowsDriver, CursesDriver, NetDriver)
  23. /// will be used when Application.Init is called. If null FakeDriver will be used. Only valid if
  24. /// <paramref name="autoInit"/> is true.
  25. /// </param>
  26. /// <param name="useFakeClipboard">
  27. /// If true, will force the use of <see cref="FakeDriver.FakeClipboard"/>. Only valid if
  28. /// <see cref="IConsoleDriver"/> == <see cref="FakeDriver"/> and <paramref name="autoInit"/> is true.
  29. /// </param>
  30. /// <param name="fakeClipboardAlwaysThrowsNotSupportedException">
  31. /// Only valid if <paramref name="autoInit"/> is true. Only
  32. /// valid if <see cref="IConsoleDriver"/> == <see cref="FakeDriver"/> and <paramref name="autoInit"/> is true.
  33. /// </param>
  34. /// <param name="fakeClipboardIsSupportedAlwaysTrue">
  35. /// Only valid if <paramref name="autoInit"/> is true. Only valid if
  36. /// <see cref="IConsoleDriver"/> == <see cref="FakeDriver"/> and <paramref name="autoInit"/> is true.
  37. /// </param>
  38. /// <param name="configLocation">Determines what config file locations <see cref="ConfigurationManager"/> will load from.</param>
  39. /// <param name="verifyShutdown">If true and <see cref="Application.Initialized"/> is true, the test will fail.</param>
  40. public AutoInitShutdownAttribute (
  41. bool autoInit = true,
  42. Type consoleDriverType = null,
  43. bool useFakeClipboard = true,
  44. bool fakeClipboardAlwaysThrowsNotSupportedException = false,
  45. bool fakeClipboardIsSupportedAlwaysTrue = false,
  46. ConfigLocations configLocation = ConfigLocations.Default, // DefaultOnly is the default for tests
  47. bool verifyShutdown = false
  48. )
  49. {
  50. AutoInit = autoInit;
  51. CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo ("en-US");
  52. _driverType = consoleDriverType ?? typeof (FakeDriver);
  53. FakeDriver.FakeBehaviors.UseFakeClipboard = useFakeClipboard;
  54. FakeDriver.FakeBehaviors.FakeClipboardAlwaysThrowsNotSupportedException =
  55. fakeClipboardAlwaysThrowsNotSupportedException;
  56. FakeDriver.FakeBehaviors.FakeClipboardIsSupportedAlwaysFalse = fakeClipboardIsSupportedAlwaysTrue;
  57. ConfigurationManager.Locations = configLocation;
  58. _verifyShutdown = verifyShutdown;
  59. }
  60. private readonly bool _verifyShutdown;
  61. private readonly Type _driverType;
  62. public override void After (MethodInfo methodUnderTest)
  63. {
  64. Debug.WriteLine ($"After: {methodUnderTest.Name}");
  65. // Turn off diagnostic flags in case some test left them on
  66. View.Diagnostics = ViewDiagnosticFlags.Off;
  67. if (AutoInit)
  68. {
  69. // try
  70. {
  71. if (!_verifyShutdown)
  72. {
  73. Application.ResetState (ignoreDisposed: true);
  74. }
  75. Application.Shutdown ();
  76. #if DEBUG_IDISPOSABLE
  77. if (View.Instances.Count == 0)
  78. {
  79. Assert.Empty (View.Instances);
  80. }
  81. else
  82. {
  83. View.Instances.Clear ();
  84. }
  85. #endif
  86. }
  87. //catch (Exception e)
  88. //{
  89. // Assert.Fail ($"Application.Shutdown threw an exception after the test exited: {e}");
  90. //}
  91. //finally
  92. {
  93. #if DEBUG_IDISPOSABLE
  94. View.Instances.Clear ();
  95. Application.ResetState (true);
  96. #endif
  97. }
  98. }
  99. // Reset to defaults
  100. ConfigurationManager.Locations = ConfigLocations.Default;
  101. ConfigurationManager.Reset ();
  102. // Enable subsequent tests that call Init to get all config files (the default).
  103. //Locations = ConfigLocations.All;
  104. }
  105. public override void Before (MethodInfo methodUnderTest)
  106. {
  107. Debug.WriteLine ($"Before: {methodUnderTest.Name}");
  108. if (AutoInit)
  109. {
  110. #if DEBUG_IDISPOSABLE
  111. View.DebugIDisposable = true;
  112. // Clear out any lingering Responder instances from previous tests
  113. if (View.Instances.Count == 0)
  114. {
  115. Assert.Empty (View.Instances);
  116. }
  117. else
  118. {
  119. View.Instances.Clear ();
  120. }
  121. #endif
  122. Application.Init ((IConsoleDriver)Activator.CreateInstance (_driverType));
  123. }
  124. }
  125. private bool AutoInit { get; }
  126. }