using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using Xunit.Sdk;
namespace UnitTests;
///
/// Enables test functions annotated with the [AutoInitShutdown] attribute to
/// automatically call Application.Init at start of the test and Application.Shutdown after the
/// test exits.
/// This is necessary because a) Application is a singleton and Init/Shutdown must be called
/// as a pair, and b) all unit test functions should be atomic..
///
[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]
public class AutoInitShutdownAttribute : BeforeAfterTestAttribute
{
///
/// Initializes a [AutoInitShutdown] attribute, which determines if/how Application.Init and Application.Shutdown
/// are automatically called Before/After a test runs.
///
/// If true, Application.Init will be called Before the test runs.
///
/// Forces the specified driver ("windows", "dotnet", "unix", or "fake") to
/// be used when Application.Init is called. If not specified FakeDriver will be used. Only valid if
/// is true.
///
public AutoInitShutdownAttribute (
bool autoInit = true,
string forceDriver = null
)
{
_autoInit = autoInit;
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo ("en-US");
_forceDriver = forceDriver;
}
private readonly string _forceDriver;
private IDisposable _v2Cleanup;
public override void After (MethodInfo methodUnderTest)
{
Debug.WriteLine ($"After: {methodUnderTest?.Name ?? "Unknown Test"}");
// Turn off diagnostic flags in case some test left them on
View.Diagnostics = ViewDiagnosticFlags.Off;
_v2Cleanup?.Dispose ();
if (_autoInit)
{
try
{
Application.Shutdown ();
#if DEBUG_IDISPOSABLE
if (View.Instances.Count == 0)
{
Assert.Empty (View.Instances);
}
else
{
View.Instances.Clear ();
}
#endif
}
//catch (Exception e)
//{
// Debug.WriteLine ($"Application.Shutdown threw an exception after the test exited: {e}");
//}
finally
{
#if DEBUG_IDISPOSABLE
View.Instances.Clear ();
Application.ResetState (true);
#endif
ApplicationImpl.SetInstance (null);
}
}
Debug.Assert (!CM.IsEnabled, "This test left ConfigurationManager enabled!");
// Force the ConfigurationManager to reset to its hardcoded defaults
CM.Disable (true);
}
public override void Before (MethodInfo methodUnderTest)
{
Debug.WriteLine ($"Before: {methodUnderTest?.Name ?? "Unknown Test"}");
Debug.Assert (!CM.IsEnabled, "A previous test left ConfigurationManager enabled!");
// Disable & force the ConfigurationManager to reset to its hardcoded defaults
CM.Disable (true);
//Debug.Assert(!CM.IsEnabled, "Some other test left ConfigurationManager enabled.");
if (_autoInit)
{
#if DEBUG_IDISPOSABLE
View.EnableDebugIDisposableAsserts = true;
// Clear out any lingering Responder instances from previous tests
if (View.Instances.Count == 0)
{
Assert.Empty (View.Instances);
}
else
{
View.Instances.Clear ();
}
#endif
if (string.IsNullOrEmpty (_forceDriver) || _forceDriver.ToLowerInvariant () == "fake")
{
var fa = new FakeApplicationFactory ();
_v2Cleanup = fa.SetupFakeApplication ();
}
else
{
Assert.Fail ("Specifying driver name not yet supported");
//Application.Init ((IDriver)Activator.CreateInstance (_forceDriver));
}
}
}
private bool _autoInit { get; }
///
/// Runs a single iteration of the main loop (layout, draw, run timed events etc.)
///
public static void RunIteration ()
{
ApplicationImpl a = (ApplicationImpl)ApplicationImpl.Instance;
a.Coordinator?.RunIteration ();
}
}