AutoInitShutdownAttribute.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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="forceDriver">
  22. /// Forces the specified driver ("windows", "dotnet", "unix", or "fake") to
  23. /// be used when Application.Init is called. If not specified FakeDriver will be used. Only valid if
  24. /// <paramref name="autoInit"/> is true.
  25. /// </param>
  26. /// <param name="verifyShutdown">If true and <see cref="Application.Initialized"/> is true, the test will fail.</param>
  27. public AutoInitShutdownAttribute (
  28. bool autoInit = true,
  29. string forceDriver = null,
  30. bool verifyShutdown = false
  31. )
  32. {
  33. AutoInit = autoInit;
  34. CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo ("en-US");
  35. _forceDriver = forceDriver;
  36. _verifyShutdown = verifyShutdown;
  37. }
  38. private readonly bool _verifyShutdown;
  39. private readonly string _forceDriver;
  40. private IDisposable _v2Cleanup;
  41. public override void After (MethodInfo methodUnderTest)
  42. {
  43. Debug.WriteLine ($"After: {methodUnderTest?.Name ?? "Unknown Test"}");
  44. // Turn off diagnostic flags in case some test left them on
  45. View.Diagnostics = ViewDiagnosticFlags.Off;
  46. _v2Cleanup?.Dispose ();
  47. if (AutoInit)
  48. {
  49. // try
  50. {
  51. if (!_verifyShutdown)
  52. {
  53. Application.ResetState (ignoreDisposed: true);
  54. }
  55. Application.Shutdown ();
  56. #if DEBUG_IDISPOSABLE
  57. if (View.Instances.Count == 0)
  58. {
  59. Assert.Empty (View.Instances);
  60. }
  61. else
  62. {
  63. View.Instances.Clear ();
  64. }
  65. #endif
  66. }
  67. //catch (Exception e)
  68. //{
  69. // Assert.Fail ($"Application.Shutdown threw an exception after the test exited: {e}");
  70. //}
  71. //finally
  72. {
  73. #if DEBUG_IDISPOSABLE
  74. View.Instances.Clear ();
  75. Application.ResetState (true);
  76. #endif
  77. }
  78. }
  79. Debug.Assert (!CM.IsEnabled, "This test left ConfigurationManager enabled!");
  80. // Force the ConfigurationManager to reset to its hardcoded defaults
  81. CM.Disable (true);
  82. }
  83. public override void Before (MethodInfo methodUnderTest)
  84. {
  85. Debug.WriteLine ($"Before: {methodUnderTest?.Name ?? "Unknown Test"}");
  86. Debug.Assert (!CM.IsEnabled, "A previous test left ConfigurationManager enabled!");
  87. // Disable & force the ConfigurationManager to reset to its hardcoded defaults
  88. CM.Disable (true);
  89. //Debug.Assert(!CM.IsEnabled, "Some other test left ConfigurationManager enabled.");
  90. if (AutoInit)
  91. {
  92. #if DEBUG_IDISPOSABLE
  93. View.EnableDebugIDisposableAsserts = true;
  94. // Clear out any lingering Responder instances from previous tests
  95. if (View.Instances.Count == 0)
  96. {
  97. Assert.Empty (View.Instances);
  98. }
  99. else
  100. {
  101. View.Instances.Clear ();
  102. }
  103. #endif
  104. if (string.IsNullOrEmpty(_forceDriver) || _forceDriver.ToLowerInvariant () == "fake")
  105. {
  106. var fa = new FakeApplicationFactory ();
  107. _v2Cleanup = fa.SetupFakeApplication ();
  108. }
  109. else
  110. {
  111. Assert.Fail ("Specifying driver name not yet supported");
  112. //Application.Init ((IDriver)Activator.CreateInstance (_forceDriver));
  113. }
  114. }
  115. }
  116. private bool AutoInit { get; }
  117. /// <summary>
  118. /// Runs a single iteration of the main loop (layout, draw, run timed events etc.)
  119. /// </summary>
  120. public static void RunIteration ()
  121. {
  122. ApplicationImpl a = (ApplicationImpl)ApplicationImpl.Instance;
  123. a.Coordinator?.RunIteration ();
  124. }
  125. }