Chromium Code Reviews| Index: visual_studio/NativeClientVSAddIn/UnitTests/PluginDebuggerHelperTest.cs |
| diff --git a/visual_studio/NativeClientVSAddIn/UnitTests/PluginDebuggerHelperTest.cs b/visual_studio/NativeClientVSAddIn/UnitTests/PluginDebuggerHelperTest.cs |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..5a3a584635a3897803a7d236258f59734906b49c |
| --- /dev/null |
| +++ b/visual_studio/NativeClientVSAddIn/UnitTests/PluginDebuggerHelperTest.cs |
| @@ -0,0 +1,554 @@ |
| +using NativeClientVSAddIn; |
| +using Microsoft.VisualStudio.TestTools.UnitTesting; |
| +using EnvDTE80; |
| +using System; |
| +using System.Collections.Generic; |
| +using System.Diagnostics; |
| +using System.IO; |
| +using System.Reflection; |
| +using System.Threading; |
| + |
| +namespace UnitTests |
| +{ |
| + /// <summary> |
| + ///This is a test class for PluginDebuggerHelperTest and is intended |
| + ///to contain all PluginDebuggerHelperTest Unit Tests |
| + ///</summary> |
| + [TestClass()] |
| + public class PluginDebuggerHelperTest |
| + { |
| + /// <summary> |
| + /// The dummy loop solution is a valid nacl/pepper plug-in VS solution |
| + /// It is copied into the testing deployment directory and opened in some tests |
| + /// Because unit-tests run in any order, the solution should not be written to |
| + /// in any tests. |
| + /// </summary> |
| + private const string DummyLoopSolution = "\\DummyLoop\\DummyLoop.sln"; |
|
Petr Hosek
2012/07/10 05:37:21
You can use non-interpreted string to avoid those
tysand
2012/07/11 05:23:46
Done.
|
| + private TestContext _testContextInstance; |
| + |
| + /// <summary> |
| + ///Gets or sets the test context which provides |
| + ///information about and functionality for the current test run. |
| + ///</summary> |
| + public TestContext TestContext |
| + { |
| + get |
| + { |
| + return _testContextInstance; |
| + } |
| + set |
| + { |
| + _testContextInstance = value; |
| + } |
| + } |
| + |
| + /// <summary> |
| + ///A test for PluginDebuggerHelper Constructor |
| + ///</summary> |
| + [TestMethod()] |
| + public void PluginDebuggerHelperConstructorTest() |
| + { |
| + // Check null dte fails |
| + try |
| + { |
| + PluginDebuggerHelper nullDte = new PluginDebuggerHelper(null); |
| + Assert.Fail("Using null DTE instance did not throw exception"); |
| + } |
| + catch (ArgumentNullException) |
| + { |
| + } |
| + catch |
| + { |
| + Assert.Fail("Using null DTE instance threw something other than ArgumentNullException"); |
| + } |
| + |
| + DTE2 dte = TestUtilities.StartVisualStudioInstance(); |
|
Petr Hosek
2012/07/10 05:37:21
Since you are using this in every single test meth
tysand
2012/07/11 05:23:46
Done.
|
| + try |
| + { |
| + PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(dte); |
| + Assert.AreEqual(dte, target._dte); |
| + Assert.IsNull(target._webServerOutputPane); |
| + Assert.IsFalse(target._isDebuggingNow); |
| + Assert.IsFalse(target._isProperlyInitialized); |
| + } |
| + finally |
| + { |
| + TestUtilities.CleanUpVisualStudioInstance(dte); |
|
Petr Hosek
2012/07/10 05:37:21
The same here, could you move this to a shared cle
tysand
2012/07/11 05:23:46
Done.
|
| + } |
| + } |
| + |
| + /// <summary> |
| + /// This unit test verifies that the gdb init file is written correctly, |
| + /// and old-existing GDB processes are cleaned up |
| + /// Verification of actual attachment is the responsibility of integration |
| + /// tests and NaCl-GDB itself |
| + ///</summary> |
| + [TestMethod()] |
| + [DeploymentItem("NativeClientVSAddIn.dll")] |
| + public void AttachNaClGDBTest() |
| + { |
| + DTE2 dte = TestUtilities.StartVisualStudioInstance(); |
| + PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(dte); |
| + string existingGDB = "AttachNaClGDBTest_existingGDB"; |
| + try |
| + { |
| + target._pluginProjectDirectory = TestContext.DeploymentDirectory; |
|
Petr Hosek
2012/07/10 05:37:21
I would turn these into properties, accessing clas
tysand
2012/07/11 05:23:46
Most methods being tested are private and don't ha
|
| + target._pluginAssembly = "fakeAssemblyString"; |
| + target._irtPath = "fakeIrtPath"; |
| + target._gdbPath = "python.exe"; |
| + target._gdbProcess = TestUtilities.StartProcessForKilling(existingGDB, 20); |
| + string existingInitFileName = Path.GetTempFileName(); |
| + target._gdbInitFileName = existingInitFileName; |
| + target._isDebuggingNow = true; |
| + target._isProperlyInitialized = true; |
| + |
| + // Visual studio won't allow adding a breakpoint unless it is associated with |
| + // an existing file and valid line number |
| + dte.Solution.Open(TestContext.DeploymentDirectory + DummyLoopSolution); |
| + string fileName = "main.cpp"; |
| + string functionName = "DummyInstance::HandleMessage"; |
| + int lineNumber = 35; |
| + dte.Debugger.Breakpoints.Add(Function: functionName); |
| + dte.Debugger.Breakpoints.Add(Line: lineNumber, File: fileName); |
| + |
| + target.AttachNaClGDB(null, new PluginFoundEventArgs(0)); |
| + |
| + Assert.IsTrue(File.Exists(target._gdbInitFileName), "Init file not written"); |
| + |
| + string[] gdbCommands = File.ReadAllLines(target._gdbInitFileName); |
| + bool functionBP = false; |
| + bool lineBP = false; |
| + |
| + // Validate that commands contain what we specified |
| + // Syntax itself is not validated since this add-in is not responsible for |
| + // the syntax and it could change |
| + foreach (string command in gdbCommands) |
| + { |
| + if (command.Contains(fileName) && command.Contains(lineNumber.ToString())) |
| + lineBP = true; |
| + if (command.Contains(functionName)) |
| + functionBP = true; |
| + } |
| + |
| + Assert.IsFalse(TestUtilities.DoesProcessExist(existingGDB, "python.exe"), "Failed to kill existing GDB process"); |
| + Assert.IsFalse(File.Exists(existingInitFileName), "Failed to delete existing temp gdb init file"); |
| + Assert.IsTrue(lineBP, "Line breakpoint not properly set"); |
| + Assert.IsTrue(functionBP, "Function breakpoint not properly set"); |
| + } |
| + finally |
| + { |
| + if (dte.Debugger.Breakpoints != null) |
| + { |
| + // Remove all breakpoints |
| + foreach(EnvDTE.Breakpoint bp in dte.Debugger.Breakpoints) |
| + bp.Delete(); |
| + } |
| + if (!String.IsNullOrEmpty(target._gdbInitFileName) && File.Exists(target._gdbInitFileName)) |
| + File.Delete(target._gdbInitFileName); |
| + if (target._gdbProcess != null && !target._gdbProcess.HasExited) |
| + target._gdbProcess.Kill(); |
| + TestUtilities.CleanUpVisualStudioInstance(dte); |
| + } |
| + } |
| + |
| + /// <summary> |
| + ///A test for FindAndAttachToPlugin |
| + ///</summary> |
| + [TestMethod()] |
| + [DeploymentItem("NativeClientVSAddIn.dll")] |
| + public void FindAndAttachToPluginTest() |
| + { |
| + DTE2 dte = TestUtilities.StartVisualStudioInstance(); |
| + try |
| + { |
| + PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(dte); |
| + target._isDebuggingNow = true; |
| + target._isProperlyInitialized = true; |
| + |
| + MockProcessSearcher processResults = new MockProcessSearcher(); |
| + uint currentProcId = (uint)System.Diagnostics.Process.GetCurrentProcess().Id; |
| + string naclCommandLine = Strings.NaClProcessTypeFlag + " " + Strings.NaClDebugFlag; |
| + target._pluginAssembly = "testAssemblyPath"; |
| + string pepperCommandLine = String.Format(Strings.PepperProcessPluginFlagFormat, target._pluginAssembly) + |
| + " " + Strings.PepperProcessTypeFlag; |
| + |
| + // Fake the list of processes on the system |
| + processResults.Results.Add(new ProcessInfo(currentProcId, currentProcId, "", "", "devenv.exe")); |
| + processResults.Results.Add(new ProcessInfo(1, currentProcId, "", "", "MyParentProcess")); |
| + processResults.Results.Add(new ProcessInfo(10, 1, "", pepperCommandLine, Strings.PepperProcessName)); |
| + processResults.Results.Add(new ProcessInfo(11, 1, "", naclCommandLine, Strings.NaClProcessName)); |
| + processResults.Results.Add(new ProcessInfo(12, 1, "", |
| + String.Format(Strings.PepperProcessPluginFlagFormat, target._pluginAssembly), |
| + Strings.PepperProcessName)); |
| + processResults.Results.Add(new ProcessInfo(13, 1, "", Strings.NaClDebugFlag, Strings.NaClProcessName)); |
| + |
| + // These two don't have this process as their parent, so they should not be attached to |
| + processResults.Results.Add(new ProcessInfo(14, 14, "", pepperCommandLine, Strings.PepperProcessName)); |
| + processResults.Results.Add(new ProcessInfo(15, 15, "", naclCommandLine, Strings.NaClProcessName)); |
| + |
| + // Set the private value to the mock object (can't use accessor since no valid cast) |
| + typeof(PluginDebuggerHelper).GetField("_processSearcher", BindingFlags.NonPublic | BindingFlags.Instance). |
| + SetValue(target.Target, processResults); |
| + |
| + // Test that the correct processes are attached to |
| + bool goodNaCl = false; |
| + bool goodPepper = false; |
| + EventHandler<PluginFoundEventArgs> handler = new EventHandler<PluginFoundEventArgs>( |
| + delegate(object unused, PluginFoundEventArgs args) |
|
Petr Hosek
2012/07/10 05:37:21
I would use lambda instead of delegate, i.e. `(unu
tysand
2012/07/11 05:23:46
Delegate seems more readable to me in this context
|
| + { |
| + switch (args.ProcessID) |
| + { |
| + case 10: |
| + if (goodPepper) |
| + Assert.Fail("Should not attach twice to same pepper process"); |
| + if (target._projectPlatformType == PluginDebuggerHelper_Accessor.ProjectPlatformType.NaCl) |
| + Assert.Fail("Attached to pepper process when NaCl was the target"); |
| + goodPepper = true; |
| + break; |
| + case 11: |
| + if (goodNaCl) |
| + Assert.Fail("Should not attach twice to same nacl process"); |
| + if (target._projectPlatformType == PluginDebuggerHelper_Accessor.ProjectPlatformType.Pepper) |
| + Assert.Fail("Attached to nacl process when pepper was the target"); |
| + goodNaCl = true; |
| + break; |
| + case 12: |
| + Assert.Fail("Should not attach to pepper process with bad args"); |
| + break; |
| + case 13: |
| + Assert.Fail("Should not attach to nacl process with bad args"); |
| + break; |
| + case 14: |
| + Assert.Fail("Should not attach to pepper process that is not descendant of Visual Studio"); |
| + break; |
| + case 15: |
| + Assert.Fail("Should not attach to nacl process that is not descendant of Visual Studio"); |
| + break; |
| + default: |
| + Assert.Fail("Should not attach to non-pepper/nacl process"); |
| + break; |
| + } |
| + }); |
| + |
| + target.add_PluginFoundEvent(handler); |
| + target._projectPlatformType = PluginDebuggerHelper_Accessor.ProjectPlatformType.Pepper; |
| + target.FindAndAttachToPlugin(null, null); |
| + target._projectPlatformType = PluginDebuggerHelper_Accessor.ProjectPlatformType.NaCl; |
| + target.FindAndAttachToPlugin(null, null); |
| + target.remove_PluginFoundEvent(handler); |
| + Assert.IsTrue(goodPepper, "Failed to attach to pepper process"); |
| + Assert.IsTrue(goodNaCl, "Failed to attach to NaCl process"); |
| + } |
| + finally |
| + { |
| + TestUtilities.CleanUpVisualStudioInstance(dte); |
| + } |
| + } |
| + |
| + /// <summary> |
| + ///A test for InitializeFromProjectSettings |
| + ///</summary> |
| + [TestMethod()] |
| + public void InitializeFromProjectSettingsTest() |
| + { |
| + DTE2 dte = TestUtilities.StartVisualStudioInstance(); |
| + try |
| + { |
| + string expectedSDKRootDir = Environment.GetEnvironmentVariable(Strings.SDKPathEnvironmentVariable); |
| + Assert.IsNotNull(expectedSDKRootDir, "SDK Path environment variable not set!"); |
| + |
| + PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(dte); |
| + target._isDebuggingNow = false; |
| + target._isProperlyInitialized = false; |
| + try |
| + { |
| + target.InitializeFromProjectSettings(); |
| + Assert.Fail("Initializing with no loaded solution shouldn't succeed"); |
| + } |
| + catch (ArgumentOutOfRangeException e) |
| + { |
| + } |
| + |
| + dte.Solution.Open(TestContext.DeploymentDirectory + DummyLoopSolution); |
| + |
| + // Set start-up project to a non-cpp project, should not initialize |
| + string badProjectUniqueName = "NotNaCl\\NotNaCl.csproj"; |
| + object[] badStartupProj = { badProjectUniqueName }; |
| + dte.Solution.SolutionBuild.StartupProjects = badStartupProj; |
| + Assert.IsFalse(target.InitializeFromProjectSettings()); |
| + Assert.IsFalse(target._isProperlyInitialized); |
| + |
| + // Set start-up project to correct C++ project, but set platform to non-nacl/pepper |
| + // Initialization should fail |
| + string projectUniqueName = "DummyLoop\\DummyLoop.vcxproj"; |
| + object[] startupProj = { projectUniqueName }; |
| + dte.Solution.SolutionBuild.StartupProjects = startupProj; |
| + TestUtilities.SetSolutionConfiguration(dte, projectUniqueName, "Debug", "Win32"); |
| + Assert.IsFalse(target.InitializeFromProjectSettings()); |
| + Assert.IsFalse(target._isProperlyInitialized); |
| + |
| + // Set platform to NaCl, should succeed |
| + TestUtilities.SetSolutionConfiguration(dte, projectUniqueName, "Debug", Strings.NaClPlatformName); |
| + Assert.IsTrue(target.InitializeFromProjectSettings()); |
| + Assert.IsTrue(target._isProperlyInitialized); |
| + Assert.AreEqual(target._projectPlatformType, PluginDebuggerHelper_Accessor.ProjectPlatformType.NaCl); |
| + Assert.AreEqual(target._debuggerType, PluginDebuggerHelper_Accessor.DebuggerType.GDB); |
| + Assert.AreEqual(target._pluginProjectDirectory, TestContext.DeploymentDirectory + "\\DummyLoop\\DummyLoop\\"); |
| + Assert.AreEqual(target._pluginAssembly, TestContext.DeploymentDirectory + "\\DummyLoop\\DummyLoop\\NaCl\\Debug\\DummyLoop.nexe"); |
| + Assert.AreEqual(target._pluginOutputDirectory, TestContext.DeploymentDirectory + "\\DummyLoop\\DummyLoop\\NaCl\\Debug\\"); |
| + Assert.AreEqual(target._sdkRootDirectory, expectedSDKRootDir); |
| + Assert.AreEqual(target._webServerExecutable, "python.exe"); |
| + //Assert.AreEqual(target._webServerArguments, ""); |
| + //Assert.AreEqual(target._gdbPath, ""); |
| + |
| + // Set platform to Pepper, should succeed |
| + TestUtilities.SetSolutionConfiguration(dte, projectUniqueName, "Debug", Strings.PepperPlatformName); |
| + Assert.IsTrue(target.InitializeFromProjectSettings()); |
| + Assert.IsTrue(target._isProperlyInitialized); |
| + Assert.AreEqual(target._projectPlatformType, PluginDebuggerHelper_Accessor.ProjectPlatformType.Pepper); |
| + Assert.AreEqual(target._debuggerType, PluginDebuggerHelper_Accessor.DebuggerType.VS); |
| + Assert.AreEqual(target._pluginProjectDirectory, TestContext.DeploymentDirectory + "\\DummyLoop\\DummyLoop\\"); |
| + Assert.AreEqual(target._pluginAssembly, TestContext.DeploymentDirectory + "\\DummyLoop\\Debug\\PPAPI\\DummyLoop.dll"); |
| + Assert.AreEqual(target._pluginOutputDirectory, TestContext.DeploymentDirectory + "\\DummyLoop\\Debug\\PPAPI\\"); |
| + Assert.AreEqual(target._sdkRootDirectory, expectedSDKRootDir); |
| + Assert.AreEqual(target._webServerExecutable, "python.exe"); |
| + //Assert.AreEqual(target._webServerArguments, ""); |
| + //Assert.AreEqual(target._gdbPath, ""); |
| + } |
| + finally |
| + { |
| + TestUtilities.CleanUpVisualStudioInstance(dte); |
| + } |
| + } |
| + |
| + /// <summary> |
| + /// Checks that VS properly attaches debugger |
| + ///</summary> |
| + [TestMethod()] |
| + [DeploymentItem("NativeClientVSAddIn.dll")] |
| + public void AttachVSDebuggerTest() |
| + { |
| + Process dummyProc = null; |
|
Petr Hosek
2012/07/10 05:37:21
You might consider wrapping the Process into using
tysand
2012/07/11 05:23:46
Done.
|
| + DTE2 dte = TestUtilities.StartVisualStudioInstance(); |
| + try |
| + { |
| + PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(dte); |
| + target._debuggerType = PluginDebuggerHelper_Accessor.DebuggerType.VS; |
| + target._projectPlatformType = PluginDebuggerHelper_Accessor.ProjectPlatformType.Pepper; |
| + target._isDebuggingNow = true; |
| + target._isProperlyInitialized = true; |
| + |
| + dummyProc = TestUtilities.StartProcessForKilling("DummyProc", 20); |
| + target.AttachVSDebugger(null, new PluginFoundEventArgs(((uint)dummyProc.Id))); |
| + |
| + bool isBeingDebugged = false; |
| + foreach (EnvDTE.Process proc in dte.Debugger.DebuggedProcesses) |
| + { |
| + if (proc.ProcessID == dummyProc.Id) |
| + isBeingDebugged = true; |
| + } |
| + Assert.IsTrue(isBeingDebugged, "Visual Studio debugger did not attach"); |
| + } |
| + finally |
| + { |
| + if (dummyProc != null && !dummyProc.HasExited) |
| + dummyProc.Kill(); |
| + |
| + TestUtilities.CleanUpVisualStudioInstance(dte); |
| + } |
| + } |
| + |
| + /// <summary> |
| + ///A test for StartDebugging |
| + ///Also implicitly tests IsDebuggerRunningTest |
| + ///</summary> |
| + [TestMethod()] |
| + public void StartDebuggingTest() |
| + { |
| + DTE2 dte = TestUtilities.StartVisualStudioInstance(); |
| + try |
| + { |
| + PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(dte); |
| + |
| + // Neutralize StartWebServer by providing dummy executable settings: |
| + target._webServerExecutable = "python.exe"; |
| + target._webServerArguments = "-c \"print 'test'\""; |
| + target._pluginProjectDirectory = TestContext.DeploymentDirectory; |
| + |
| + // Have the timer call a function to set success to true |
| + ManualResetEvent finderSuccess = new ManualResetEvent(false); |
| + target._pluginFinderTimer = new System.Windows.Forms.Timer(); |
| + target._pluginFinderTimer.Tick += new EventHandler(delegate(object a, EventArgs b) { finderSuccess.Set(); }); |
|
Petr Hosek
2012/07/10 05:37:21
I would use lambda here.
tysand
2012/07/11 05:23:46
Done.
|
| + |
| + // Check that nothing happens when not initialized |
| + target._isDebuggingNow = false; |
| + target._isProperlyInitialized = false; |
| + target.StartDebugging(); |
| + Assert.IsFalse(target.IsDebuggerRunning, "Debugging started when not properly initialized"); |
| + |
| + // Properly start debugging and wait for event signal |
| + target._isProperlyInitialized = true; |
| + target.StartDebugging(); |
| + |
| + // Pump events waiting for signal, time-out after 10 seconds |
| + bool success = false; |
| + for (int i = 0; i < 20; i++) |
| + { |
| + System.Windows.Forms.Application.DoEvents(); |
| + if (finderSuccess.WaitOne(500)) |
| + { |
| + success = true; |
| + break; |
| + } |
| + } |
|
Petr Hosek
2012/07/10 05:37:21
When handling events, you might consider using Rea
tysand
2012/07/11 05:23:46
Would require an external install in order to use
|
| + |
| + Assert.IsTrue(success, "Plug-in finder timer did not fire"); |
| + Assert.IsTrue(target.IsDebuggerRunning, "IsDebuggerRunning not true after debugging started"); |
| + } |
| + finally |
| + { |
| + TestUtilities.CleanUpVisualStudioInstance(dte); |
| + } |
| + } |
| + |
| + /// <summary> |
| + /// Tests that StartWebServer executes _webServerExecutable with _webServerArguments |
| + /// as arguments, sets the working directory to the project directory, and hooks |
| + /// up stdout and stderr from the web server to the Web Server output panel in VS. |
| + /// This test implicitly covers WebServerMessageReceive |
| + ///</summary> |
| + [TestMethod()] |
| + [DeploymentItem("NativeClientVSAddIn.dll")] |
| + public void StartWebServerTest() |
| + { |
| + DTE2 dte = TestUtilities.StartVisualStudioInstance(); |
| + PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(dte); |
| + try |
| + { |
| + string successMessage = "successful test!"; |
| + string stderrMessage = "stderr test"; |
| + target._webServerExecutable = "python.exe"; |
| + |
| + // To save pain, if modifying this in the future avoid special characters, |
| + // or make sure to double escape them. Ex: \n --> \\n |
| + string program = |
| + "import os;" + |
| + "import sys;" + |
| + String.Format("sys.stdout.write('{0}');", successMessage) + |
| + String.Format("sys.stderr.write('{0}');", stderrMessage) + |
| + "sys.stdout.write(os.getcwd());" + |
| + "sys.stdout.flush();" + |
| + "sys.stderr.flush()"; |
| + target._webServerArguments = String.Format("-c \"{0}\"", program); |
| + target._pluginProjectDirectory = TestContext.DeploymentDirectory; |
| + target._isDebuggingNow = false; |
| + target._isProperlyInitialized = true; |
| + target.StartWebServer(); |
| + |
| + // Check that the output pane exists |
| + EnvDTE.OutputWindowPane window = dte.ToolWindows.OutputWindow.OutputWindowPanes.Item( |
| + Strings.WebServerOutputWindowTitle); |
| + Assert.IsNotNull(window, "Web server output pane failed to create"); |
| + |
| + // Wait for results to arrive for up to 10 seconds, checking every 0.5 seconds |
| + string result = TestUtilities.GetPaneText(target._webServerOutputPane); |
| + for (int repeat = 0; repeat < 20; repeat++) |
| + { |
| + if (result != null && |
| + result.Contains(successMessage) && |
| + result.Contains(stderrMessage) && |
| + result.Contains(TestContext.DeploymentDirectory)) |
| + break; |
| + Thread.Sleep(500); |
| + result = TestUtilities.GetPaneText(target._webServerOutputPane); |
| + } |
| + |
| + Assert.IsFalse(String.IsNullOrEmpty(result), "Nothing printed to output pane"); |
| + StringAssert.Contains(result, successMessage, "Executable did not successfully run given arguments"); |
| + StringAssert.Contains(result, stderrMessage, "Standard error message was not captured"); |
| + StringAssert.Contains(result, TestContext.DeploymentDirectory, "Web server working directory was not set to project directory"); |
| + } |
| + finally |
| + { |
| + if (!target._webServer.WaitForExit(1000)) |
| + target._webServer.Kill(); |
| + TestUtilities.CleanUpVisualStudioInstance(dte); |
| + } |
| + } |
| + |
| + /// <summary> |
| + /// Ensures that StopDebugging() kills GDB and the web server, and resets the state of |
| + /// PluginDebuggerHelper to before debugging started |
| + /// Implicitly tests KillGDBProcess() |
| + ///</summary> |
| + [TestMethod()] |
| + public void StopDebuggingTest() |
| + { |
| + DTE2 dte = TestUtilities.StartVisualStudioInstance(); |
| + try |
| + { |
| + PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(dte); |
| + string webServerIdentifier = "StartVisualStudioInstance_TestWebServer"; |
| + string gdbIdentifier = "StartVisualStudioInstance_TestGDB"; |
| + |
| + // Setup up items that should exist given a successful calling of StartDebugging() |
| + target._gdbInitFileName = Path.GetTempFileName(); |
| + target._isDebuggingNow = true; |
| + target._pluginFinderForbiddenPids.Add(123); |
| + target._webServer = TestUtilities.StartProcessForKilling(webServerIdentifier, 20); |
| + target._gdbProcess = TestUtilities.StartProcessForKilling(gdbIdentifier, 20); |
| + target._isProperlyInitialized = true; |
| + |
| + target.StopDebugging(); |
| + |
| + Assert.IsFalse(TestUtilities.DoesProcessExist(webServerIdentifier, "python.exe"), "Failed to kill web server process"); |
| + Assert.IsFalse(TestUtilities.DoesProcessExist(gdbIdentifier, "python.exe"), "Failed to kill gdb process"); |
| + Assert.IsFalse(target.IsDebuggerRunning, "Failed to set debug running state to false"); |
| + Assert.IsFalse(File.Exists(target._gdbInitFileName), "Failed to delete temp gdb init file"); |
| + Assert.IsFalse(target._isProperlyInitialized, "Failed to set initialized state to false"); |
| + Assert.IsTrue(target._pluginFinderForbiddenPids.Count == 0, "Plugin finder Process IDs not cleared"); |
| + Assert.IsFalse(target._pluginFinderTimer.Enabled, "Plug-in finder timer not stopped"); |
| + } |
| + finally |
| + { |
| + TestUtilities.CleanUpVisualStudioInstance(dte); |
| + } |
| + } |
| + |
| + /// <summary> |
| + ///A test for WebServerWriteLine |
| + ///</summary> |
| + [TestMethod()] |
| + [DeploymentItem("NativeClientVSAddIn.dll")] |
| + public void WebServerWriteLineTest() |
| + { |
| + DTE2 dte = TestUtilities.StartVisualStudioInstance(); |
| + try |
| + { |
| + PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(dte); |
| + string successMessage = "successful test!"; |
| + target._webServerOutputPane = dte.ToolWindows.OutputWindow.OutputWindowPanes.Add( |
| + Strings.WebServerOutputWindowTitle); |
| + target._isDebuggingNow = true; |
| + target._isProperlyInitialized = true; |
| + target.WebServerWriteLine(successMessage); |
| + string result = TestUtilities.GetPaneText(target._webServerOutputPane); |
| + |
| + // Wait for results to arrive for up to 10 seconds, checking every 0.5 seconds |
| + for (int repeat = 0; repeat < 20; repeat++) |
| + { |
| + if (result != null && |
| + result.Contains(successMessage)) |
| + break; |
| + Thread.Sleep(500); |
| + result = TestUtilities.GetPaneText(target._webServerOutputPane); |
| + } |
| + StringAssert.Contains(result, successMessage, "Message failed to print"); |
| + } |
| + finally |
| + { |
| + TestUtilities.CleanUpVisualStudioInstance(dte); |
| + } |
| + } |
| + } |
| +} |