using Microsoft.VisualStudio.Imaging;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace TestExecWin_VS2022
{
public class MyToolWindow : BaseToolWindow<MyToolWindow>, IEventReceiver, IMainEvents
{
private VisualStudioConnector m_vsConnector;
private SourceFileParser m_parser;
private int m_outputLevel = 1;
private bool m_writeThreadId = false;
private ProjectInfo m_projectInfo = new ProjectInfo();
private bool m_initialMessageWasDisplayed = false;
public MyToolWindow()
{
MyGlobals.myEventReceiver = this;
MyGlobals.myMainEvents = this;
}
public override string GetTitle(int toolWindowId) => "TestExecWindow";
public override Type PaneType => typeof(Pane);
public override Task<FrameworkElement> CreateAsync(int toolWindowId, CancellationToken cancellationToken)
{
return Task.FromResult<FrameworkElement>(new MyToolWindowControl());
}
public void OnGuiIsStarted()
{
m_vsConnector = new VisualStudioConnector(this, this);
m_parser = new SourceFileParser(this);
MyGlobals.myExecutor = new Executor(this, this);
OnRefreshAll();
}
void IMainEvents.OnSettingsHaveChanged()
{
Gui().SomeSettingsExternallyChanged();
WriteOptions();
}
public void OnRefreshAll()
{
Gui().TriggerDelayedRefresh();
}
void IMainEvents.OnRefreshNow()
{
if (Gui().TestIsRunning())
{
string info = "WARNING: Ignoring change of startup project while test is running";
WriteLine(1, info);
return;
}
ThreadHelper.ThrowIfNotOnUIThread();
RefreshAll();
}
void IMainEvents.OnSetOutputLevel(int in_level)
{
m_outputLevel = in_level;
m_writeThreadId = m_outputLevel >= 2;
}
void IMainEvents.OnStartBuilding()
{
ThreadHelper.ThrowIfNotOnUIThread();
m_vsConnector.BuildProject();
}
void IMainEvents.OnBuildTerminated(bool success)
{
ThreadHelper.ThrowIfNotOnUIThread();
Gui().BuildTerminated(success);
}
void IMainEvents.OnStartTest(string exePath, string args, string workDir)
{
MyGlobals.myExecutor.StartProcess(exePath, args, workDir); ;
}
public void OnTestTerminated(bool in_success, string in_args, bool in_memLeaksDetected, TimeSpan in_executionTime)
{
Microsoft.VisualStudio.Shell.ThreadHelper.JoinableTaskFactory.Run(async delegate
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
Gui().TestTerminatedWithinGuiThread(in_success, "", in_args, in_memLeaksDetected, in_executionTime);
});
}
void IMainEvents.OnStopAll()
{
ThreadHelper.ThrowIfNotOnUIThread();
m_vsConnector.StopBuildingProject();
MyGlobals.myExecutor.KillRunningProcess();
}
void IMainEvents.OnStartDebugging(string in_cmdLineParams)
{
ThreadHelper.ThrowIfNotOnUIThread();
m_vsConnector.StartDebugging(in_cmdLineParams);
}
void IMainEvents.OnOpenProtocolFile()
{
ThreadHelper.ThrowIfNotOnUIThread();
string protocolFilePath = m_projectInfo.GetExePath();
protocolFilePath = protocolFilePath.Replace(".exe", ".out");
if (!System.IO.File.Exists(protocolFilePath))
{
MsgBox("Test protocol not found: " + protocolFilePath);
}
else
{
m_vsConnector.OpenFile(protocolFilePath);
}
}
void IMainEvents.OnOpenSourceFile(string in_fullFileName, int in_lineNum)
{
ThreadHelper.ThrowIfNotOnUIThread();
if (!System.IO.File.Exists(in_fullFileName))
{
MsgBox("Sourcefile not found: " + in_fullFileName);
}
else
{
m_vsConnector.OpenFile(in_fullFileName, in_lineNum);
}
}
string IMainEvents.OnGetExecutablesFromCurrentSolution()
{
ThreadHelper.ThrowIfNotOnUIThread();
return m_vsConnector.GetExecutablesFromCurrentSolution();
}
public void WriteLine(int in_outputLevel, String in_info)
{
if (in_outputLevel <= m_outputLevel)
{
if (m_writeThreadId)
{
Gui().AddInfoToEventList(Services.GetThreadIdPrompt() + in_info);
}
else
{
Gui().AddInfoToEventList(in_info);
}
}
}
public void MsgBox(string in_info)
{
System.Windows.MessageBox.Show(in_info, "Info");
}
private void RefreshAll()
{
WriteLine(3, "RefreshAll-Begin");
try
{
ThreadHelper.ThrowIfNotOnUIThread();
if(!m_initialMessageWasDisplayed)
{
m_initialMessageWasDisplayed = true;
var options = Services.GetOptions();
WriteLine(1, "Options: Build before test=" + options.BuildSolutionBeforeStartingTest.ToString()
+ ", Check for memory leaks = " + options.CheckForMemoryLeaks.ToString());
}
m_projectInfo = new ProjectInfo();
if (!m_vsConnector.ReadSettingsOfStartupProject(m_projectInfo))
{
WriteLine(2, "WARNING: There is no startup project defined or the project settings are not accessible!");
return;
}
m_parser.ScanProjectDir(m_projectInfo);
Gui().SetTestInfo(m_projectInfo);
WriteLine(1, "Detected project " + m_projectInfo.project + " (" + m_projectInfo.config + ")"
+ ", type is " + m_projectInfo.appType
+ ", " + m_projectInfo.testGroups.Count + " test groups, "
+ m_projectInfo.testFuncs.Count + " test funcs");
}
catch (Exception e)
{
string info = "EXCEPTION: " + e.ToString();
WriteLine(1, info);
}
WriteLine(3, "RefreshAll-End");
}
private void WriteOptions()
{
var options = Services.GetOptions();
WriteLine(2, "Options: Build before test=" + options.BuildSolutionBeforeStartingTest.ToString()
+ ", Check for memory leaks = " + options.CheckForMemoryLeaks.ToString());
WriteLine(2, "Options: Limit CPU for std out =" + options.LimitCpuForStdOut.ToString());
WriteLine(2, "Options: Run until failure =" + options.RunUntilFailure.ToString());
}
MyToolWindowControl Gui()
{
return MyGlobals.myToolWindowControl;
}
[Guid("8b4ef7af-4568-4c07-ba13-89dd69794c1f")]
internal class Pane : ToolWindowPane
{
public Pane()
{
BitmapImageMoniker = KnownMonikers.ConsoleTest;
}
}
}
}