using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestExecWin_VS2022
{
class Executor : IExecute
{
private IMainEvents m_mainEvents;
private IEventReceiver m_eventReceiver;
private System.Diagnostics.Process m_process = null;
private bool m_processStarted = false;
private EnvDTE.OutputWindowPane m_outputPane = null;
bool m_catchStdOutAndStdErr = true;
bool m_getNotificationWhenProcessTerminates = true;
private bool m_checkForMemoryLeaks = false;
public Executor(IMainEvents in_mainEvents, IEventReceiver in_eventReceiver)
{
m_mainEvents = in_mainEvents;
m_eventReceiver = in_eventReceiver;
}
public void SetMemLeakCheck(bool in_state)
{
m_checkForMemoryLeaks = in_state;
}
public void StartProcess(string exePath, string args, string workDir)
{
try
{
string argsToUse = "";
if (args != null)
{
argsToUse = args;
}
ThreadHelper.ThrowIfNotOnUIThread();
if (!System.IO.File.Exists(exePath))
{
m_mainEvents.OnTestTerminated(false, exePath, false, new TimeSpan(0));
WriteLine(1, "Executable not found: " + exePath);
return;
}
if (m_outputPane == null)
{
EnvDTE.OutputWindow ow = MyGlobals.myDTE.ToolWindows.OutputWindow;
m_outputPane = ow.OutputWindowPanes.Add("Run UnitTest");
}
m_outputPane.Activate();
m_outputPane.Clear();
m_process = new System.Diagnostics.Process();
m_process.StartInfo.FileName = exePath;
m_process.StartInfo.WorkingDirectory = workDir;
m_process.StartInfo.Arguments = argsToUse.Trim();
if (m_getNotificationWhenProcessTerminates)
{
m_process.Exited += new System.EventHandler(Process_Exited);
m_process.EnableRaisingEvents = true;
}
if (m_catchStdOutAndStdErr)
{
m_process.StartInfo.UseShellExecute = false;
m_process.StartInfo.RedirectStandardOutput = true;
m_process.StartInfo.RedirectStandardError = true;
m_process.StartInfo.CreateNoWindow = true;
m_process.OutputDataReceived += new System.Diagnostics.
DataReceivedEventHandler(StandardOutputReceiver);
m_process.ErrorDataReceived += new System.Diagnostics.
DataReceivedEventHandler(StandardErrorReceiver);
}
m_process.Start();
m_processStarted = true;
if (m_catchStdOutAndStdErr)
{
m_process.BeginOutputReadLine();
m_process.BeginErrorReadLine();
}
WriteLine(2, "Started " + m_process.StartInfo.FileName);
}
catch (Exception e)
{
string info = "EXCEPTION: Could not start executable " + exePath + " " + e.ToString();
WriteLine(1, info);
m_mainEvents.OnTestTerminated(false, exePath, false, new TimeSpan(0));
}
}
public void Process_Exited(object sender, System.EventArgs e)
{
m_processStarted = false;
string info = string.Format("Exit time: {0}" +
" Exit code: {1}", m_process.ExitTime, m_process.ExitCode);
TimeSpan executionTime = m_process.ExitTime - m_process.StartTime;
WriteLine(2, info);
System.Threading.Thread.Sleep(500);
Microsoft.VisualStudio.Shell.ThreadHelper.JoinableTaskFactory.Run(async delegate
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
Process_Exited_MainThread(executionTime);
});
}
private void Process_Exited_MainThread(TimeSpan executionTime)
{
try
{
ThreadHelper.ThrowIfNotOnUIThread();
bool memLeaksDetected = false;
if (m_checkForMemoryLeaks)
{
WriteLine(3, "Process_Exited_MainThread: Checking mem leaks...");
var sel = m_outputPane.TextDocument.Selection;
WriteLine(3, "Process_Exited_MainThread: selection acquired");
sel.SelectAll();
WriteLine(3, "Process_Exited_MainThread: all selected");
if ((sel.Text.Contains("Detected memory leaks")) || (sel.Text.Contains("Object dump complete")))
{
memLeaksDetected = true;
WriteLine(3, "Process_Exited_MainThread: ERROR: Memory leaks detected!");
}
}
m_mainEvents.OnTestTerminated(m_process.ExitCode == 0, m_process.StartInfo.Arguments, memLeaksDetected, executionTime);
}
catch (Exception)
{
string info = "EXCEPTION within Process_Exited: ";
WriteLine(1, info);
m_mainEvents.OnTestTerminated(false, m_process.StartInfo.Arguments, false, new TimeSpan(0));
}
}
public void KillRunningProcess()
{
try
{
if (!m_processStarted)
{
WriteLine(2, "Executor: There is no process to kill!");
return;
}
WriteLine(1, "Killing " + m_process.ProcessName);
m_process.Kill();
}
catch (Exception e)
{
string info = "EXCEPTION: " + e.ToString();
WriteLine(2, info);
m_mainEvents.OnTestTerminated(false, m_process.StartInfo.Arguments, false, new TimeSpan(0));
}
}
private void StandardOutputReceiver(object sendingProcess,
System.Diagnostics.DataReceivedEventArgs outLine)
{
if (Services.GetOptions().LimitCpuForStdOut)
{
System.Threading.Thread.Yield();
}
if (!string.IsNullOrEmpty(outLine.Data))
{
Microsoft.VisualStudio.Shell.ThreadHelper.JoinableTaskFactory.Run(async delegate
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
if (m_outputPane != null)
m_outputPane.OutputString(outLine.Data + System.Environment.NewLine);
});
}
}
private void StandardErrorReceiver(object sendingProcess,
System.Diagnostics.DataReceivedEventArgs errLine)
{
if (Services.GetOptions().LimitCpuForStdOut)
{
System.Threading.Thread.Yield();
}
if (!string.IsNullOrEmpty(errLine.Data))
{
Microsoft.VisualStudio.Shell.ThreadHelper.JoinableTaskFactory.Run(async delegate
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
if (m_outputPane != null)
m_outputPane.OutputString("Error> " + errLine.Data + System.Environment.NewLine);
});
}
}
private void WriteLine(int in_outputLevel, String in_info)
{
m_eventReceiver.WriteLine(in_outputLevel, in_info);
}
}
}