NUnitTestAssemblyRunner
Implementation of ITestAssemblyRunner
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;
using NUnit.Framework.Internal.Execution;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Security;
using System.Threading;
using System.Windows.Forms;
namespace NUnit.Framework.Api
{
public class NUnitTestAssemblyRunner : ITestAssemblyRunner
{
private static Logger log = InternalTrace.GetLogger("DefaultTestAssemblyRunner");
private ITestAssemblyBuilder _builder;
private ManualResetEvent _runComplete = new ManualResetEvent(false);
private TextWriter _savedOut;
private TextWriter _savedErr;
private EventPump _pump;
public static int DefaultLevelOfParallelism => Math.Max(Environment.ProcessorCount, 2);
public ITest LoadedTest { get; set; }
public ITestResult Result {
get {
if (TopLevelWorkItem != null)
return TopLevelWorkItem.Result;
return null;
}
}
public bool IsTestLoaded => LoadedTest != null;
public bool IsTestRunning {
get {
if (TopLevelWorkItem != null)
return TopLevelWorkItem.State == WorkItemState.Running;
return false;
}
}
public bool IsTestComplete {
get {
if (TopLevelWorkItem != null)
return TopLevelWorkItem.State == WorkItemState.Complete;
return false;
}
}
private IDictionary<string, object> Settings { get; set; }
private WorkItem TopLevelWorkItem { get; set; }
private TestExecutionContext Context { get; set; }
public NUnitTestAssemblyRunner(ITestAssemblyBuilder builder)
{
_builder = builder;
}
public ITest Load(string assemblyName, IDictionary<string, object> settings)
{
Settings = settings;
if (settings.ContainsKey("RandomSeed"))
Randomizer.InitialSeed = (int)settings["RandomSeed"];
return LoadedTest = _builder.Build(assemblyName, settings);
}
public ITest Load(Assembly assembly, IDictionary<string, object> settings)
{
Settings = settings;
if (settings.ContainsKey("RandomSeed"))
Randomizer.InitialSeed = (int)settings["RandomSeed"];
return LoadedTest = _builder.Build(assembly, settings);
}
public int CountTestCases(ITestFilter filter)
{
if (LoadedTest == null)
throw new InvalidOperationException("The CountTestCases method was called but no test has been loaded");
return CountTestCases(LoadedTest, filter);
}
public ITestResult Run(ITestListener listener, ITestFilter filter)
{
RunAsync(listener, filter);
WaitForCompletion(-1);
return Result;
}
public void RunAsync(ITestListener listener, ITestFilter filter)
{
log.Info("Running tests");
if (LoadedTest == null)
throw new InvalidOperationException("The Run method was called but no test has been loaded");
_runComplete.Reset();
CreateTestExecutionContext(listener);
TopLevelWorkItem = WorkItem.CreateWorkItem(LoadedTest, filter);
TopLevelWorkItem.InitializeContext(Context);
TopLevelWorkItem.Completed += OnRunCompleted;
StartRun(listener);
}
public bool WaitForCompletion(int timeout)
{
return _runComplete.WaitOne(timeout, false);
}
public void StopRun(bool force)
{
if (IsTestRunning) {
Context.ExecutionStatus = ((!force) ? TestExecutionStatus.StopRequested : TestExecutionStatus.AbortRequested);
Context.Dispatcher.CancelRun(force);
}
}
private void StartRun(ITestListener listener)
{
_savedOut = Console.Out;
_savedErr = Console.Error;
Console.SetOut(new TextCapture(Console.Out));
Console.SetError(new EventListenerTextWriter("Error", Console.Error));
if (!Settings.ContainsKey("SynchronousEvents") || !(bool)Settings["SynchronousEvents"]) {
QueuingEventListener queuingEventListener = new QueuingEventListener();
Context.Listener = queuingEventListener;
_pump = new EventPump(listener, queuingEventListener.Events);
_pump.Start();
}
if (!Debugger.IsAttached && Settings.ContainsKey("DebugTests") && (bool)Settings["DebugTests"])
Debugger.Launch();
if (Settings.ContainsKey("PauseBeforeRun") && (bool)Settings["PauseBeforeRun"])
PauseBeforeRun();
Context.Dispatcher.Dispatch(TopLevelWorkItem);
}
private void CreateTestExecutionContext(ITestListener listener)
{
Context = new TestExecutionContext();
if (Settings.ContainsKey("DefaultTimeout"))
Context.TestCaseTimeout = (int)Settings["DefaultTimeout"];
if (Settings.ContainsKey("StopOnError"))
Context.StopOnError = (bool)Settings["StopOnError"];
if (Settings.ContainsKey("WorkDirectory"))
Context.WorkDirectory = (string)Settings["WorkDirectory"];
else
Context.WorkDirectory = Directory.GetCurrentDirectory();
Context.Listener = listener;
int levelOfParallelism = GetLevelOfParallelism();
if (levelOfParallelism > 0)
Context.Dispatcher = new ParallelWorkItemDispatcher(levelOfParallelism);
else
Context.Dispatcher = new SimpleWorkItemDispatcher();
}
private void OnRunCompleted(object sender, EventArgs e)
{
if (_pump != null)
_pump.Dispose();
Console.SetOut(_savedOut);
Console.SetError(_savedErr);
_runComplete.Set();
}
private int CountTestCases(ITest test, ITestFilter filter)
{
if (!test.IsSuite)
return 1;
int num = 0;
foreach (ITest test2 in test.Tests) {
if (filter.Pass(test2))
num += CountTestCases(test2, filter);
}
return num;
}
private int GetLevelOfParallelism()
{
if (!Settings.ContainsKey("NumberOfTestWorkers")) {
if (!LoadedTest.Properties.ContainsKey("LevelOfParallelism"))
return DefaultLevelOfParallelism;
return (int)LoadedTest.Properties.Get("LevelOfParallelism");
}
return (int)Settings["NumberOfTestWorkers"];
}
[SecuritySafeCritical]
private static void PauseBeforeRun()
{
Process currentProcess = Process.GetCurrentProcess();
MessageBox.Show($"""{currentProcess.ProcessName}""{currentProcess.Id}""", currentProcess.ProcessName, 0, 64);
}
}
}