internal UnitTestResult RunUnitTest (UnitTest test, string suiteName, string pathName, string testName, TestContext testContext)
		{
			var runnerExe = GetCustomConsoleRunnerCommand ();
			if (runnerExe != null)
				return RunWithConsoleRunner (runnerExe, test, suiteName, pathName, testName, testContext);

			ExternalTestRunner runner = (ExternalTestRunner)Runtime.ProcessService.CreateExternalProcessObject (typeof(ExternalTestRunner), testContext.ExecutionContext, UserAssemblyPaths);
			LocalTestMonitor localMonitor = new LocalTestMonitor (testContext, test, suiteName, testName != null);

			ITestFilter filter = null;
			if (test != null) {
				if (test is UnitTestGroup) {
					var categoryOptions = (NUnitCategoryOptions) test.GetOptions (typeof(NUnitCategoryOptions));
					if (categoryOptions.EnableFilter && categoryOptions.Categories.Count > 0) {
						string[] cats = new string [categoryOptions.Categories.Count];
						categoryOptions.Categories.CopyTo (cats, 0);
						filter = new CategoryFilter (cats);
						if (categoryOptions.Exclude)
							filter = new NotFilter (filter);
					} else {
						filter = new TestNameFilter (CollectTests ((UnitTestGroup)test));
					}
				} else {
					filter = new TestNameFilter (test.TestId);
				}
			}

			RunData rd = new RunData ();
			rd.Runner = runner;
			rd.Test = this;
			rd.LocalMonitor = localMonitor;
			testContext.Monitor.CancelRequested += new TestHandler (rd.Cancel);

			UnitTestResult result;
			var crashLogFile = Path.GetTempFileName ();

			try {
				if (string.IsNullOrEmpty (AssemblyPath)) {
					string msg = GettextCatalog.GetString ("Could not get a valid path to the assembly. There may be a conflict in the project configurations.");
					throw new Exception (msg);
				}
				System.Runtime.Remoting.RemotingServices.Marshal (localMonitor, null, typeof (IRemoteEventListener));

				string testRunnerAssembly, testRunnerType;
				GetCustomTestRunner (out testRunnerAssembly, out testRunnerType);

				result = runner.Run (localMonitor, filter, AssemblyPath, "", new List<string> (SupportAssemblies), testRunnerType, testRunnerAssembly, crashLogFile);
				if (testName != null)
					result = localMonitor.SingleTestResult;
				
				ReportCrash (testContext, crashLogFile);
				
			} catch (Exception ex) {
				if (ReportCrash (testContext, crashLogFile)) {
					result = UnitTestResult.CreateFailure (GettextCatalog.GetString ("Unhandled exception"), null);
				}
				else if (!localMonitor.Canceled) {
					LoggingService.LogError (ex.ToString ());
					if (localMonitor.RunningTest != null) {
						RuntimeErrorCleanup (testContext, localMonitor.RunningTest, ex);
					} else {
						testContext.Monitor.ReportRuntimeError (null, ex);
						throw;
					}
					result = UnitTestResult.CreateFailure (ex);
				} else {
					result = UnitTestResult.CreateFailure (GettextCatalog.GetString ("Canceled"), null);
				}
			} finally {
				File.Delete (crashLogFile);
				testContext.Monitor.CancelRequested -= new TestHandler (rd.Cancel);
				runner.Dispose ();
				System.Runtime.Remoting.RemotingServices.Disconnect (localMonitor);
			}
			
			return result;
		}
		internal UnitTestResult RunUnitTest (UnitTest test, string suiteName, string testName, TestContext testContext)
		{
			ExternalTestRunner runner = (ExternalTestRunner) Runtime.ProcessService.CreateExternalProcessObject (typeof(ExternalTestRunner), testContext.ExecutionContext);
			LocalTestMonitor localMonitor = new LocalTestMonitor (testContext, runner, test, suiteName, testName != null);
			
			ITestFilter filter = null;
			
			if (testName != null) {
				filter = new TestNameFilter (suiteName + "." + testName);
			} else {
				NUnitCategoryOptions categoryOptions = (NUnitCategoryOptions) test.GetOptions (typeof(NUnitCategoryOptions));
				if (categoryOptions.EnableFilter && categoryOptions.Categories.Count > 0) {
					string[] cats = new string [categoryOptions.Categories.Count];
					categoryOptions.Categories.CopyTo (cats, 0);
					filter = new CategoryFilter (cats);
					if (categoryOptions.Exclude)
						filter = new NotFilter (filter);
				}
			}
			
			RunData rd = new RunData ();
			rd.Runner = runner;
			rd.Test = this;
			rd.LocalMonitor = localMonitor;
			testContext.Monitor.CancelRequested += new TestHandler (rd.Cancel);
			
			UnitTestResult result;
			
			try {
				if (string.IsNullOrEmpty (AssemblyPath)) {
					string msg = GettextCatalog.GetString ("Could not get a valid path to the assembly. There may be a conflict in the project configurations.");
					throw new Exception (msg);
				}
				System.Runtime.Remoting.RemotingServices.Marshal (localMonitor, null, typeof (IRemoteEventListener));
				result = runner.Run (localMonitor, filter, AssemblyPath, suiteName, new List<string> (SupportAssemblies));
				if (testName != null)
					result = localMonitor.SingleTestResult;
			} catch (Exception ex) {
				if (!localMonitor.Canceled) {
					LoggingService.LogError (ex.ToString ());
					if (localMonitor.RunningTest != null) {
						RuntimeErrorCleanup (testContext, localMonitor.RunningTest, ex);
					} else {
						testContext.Monitor.ReportRuntimeError (null, ex);
						throw ex;
					}
					result = UnitTestResult.CreateFailure (ex);
				} else {
					result = UnitTestResult.CreateFailure (GettextCatalog.GetString ("Canceled"), null);
				}
			} finally {
				testContext.Monitor.CancelRequested -= new TestHandler (rd.Cancel);
				runner.Dispose ();
				System.Runtime.Remoting.RemotingServices.Disconnect (localMonitor);
			}
			
			return result;
		}
		UnitTestResult RunWithConsoleRunner (ProcessExecutionCommand cmd, UnitTest test, string suiteName, string pathName, string testName, TestContext testContext)
		{
			var outFile = Path.GetTempFileName ();
			LocalConsole cons = new LocalConsole ();

			try {
				MonoDevelop.NUnit.External.TcpTestListener tcpListener = null;
				LocalTestMonitor localMonitor = new LocalTestMonitor (testContext, test, suiteName, testName != null);

				if (!string.IsNullOrEmpty (cmd.Arguments))
					cmd.Arguments += " ";
				cmd.Arguments += "\"-xml=" + outFile + "\" " + AssemblyPath;

				bool automaticUpdates = cmd.Command != null && (cmd.Command.Contains ("GuiUnit") || (cmd.Command.Contains ("mdtool.exe") && cmd.Arguments.Contains ("run-md-tests")));
				if (!string.IsNullOrEmpty(pathName))
					cmd.Arguments += " -run=" + test.TestId;
				if (automaticUpdates) {
					tcpListener = new MonoDevelop.NUnit.External.TcpTestListener (localMonitor, suiteName);
					cmd.Arguments += " -port=" + tcpListener.Port;
				}

				// Note that we always dispose the tcp listener as we don't want it listening
				// forever if the test runner does not try to connect to it
				using (tcpListener) {
					using (var p = testContext.ExecutionContext.Execute (cmd, cons)) {
						testContext.Monitor.CancelRequested += p.Cancel;
						if (testContext.Monitor.IsCancelRequested)
							p.Cancel ();
						p.WaitForCompleted ();
						testContext.Monitor.CancelRequested -= p.Cancel;
					}
					
					if (new FileInfo (outFile).Length == 0)
						throw new Exception ("Command failed");
				}

				// mdtool.exe does not necessarily guarantee we get automatic updates. It just guarantees
				// that if guiunit is being used then it will give us updates. If you have a regular test
				// assembly compiled against nunit.framework.dll 
				if (automaticUpdates && tcpListener.HasReceivedConnection) {
					if (testName != null)
						return localMonitor.SingleTestResult;
					return test.GetLastResult ();
				}

				XDocument doc = XDocument.Load (outFile);

				if (doc.Root != null) {
					var root = doc.Root.Elements ("test-suite").FirstOrDefault ();
					if (root != null) {
						cons.SetDone ();
						var ot = cons.Out.ReadToEnd ();
						var et = cons.Error.ReadToEnd ();
						testContext.Monitor.WriteGlobalLog (ot);
						if (!string.IsNullOrEmpty (et)) {
							testContext.Monitor.WriteGlobalLog ("ERROR:\n");
							testContext.Monitor.WriteGlobalLog (et);
						}

						bool macunitStyle = doc.Root.Element ("environment") != null && doc.Root.Element ("environment").Attribute ("macunit-version") != null;
						var result = ReportXmlResult (localMonitor, root, "", macunitStyle);
						if (testName != null)
							result = localMonitor.SingleTestResult;
						return result;
					}
				}
				throw new Exception ("Test results could not be parsed.");
			} catch (Exception ex) {
				cons.SetDone ();
				var ot = cons.Out.ReadToEnd ();
				var et = cons.Error.ReadToEnd ();
				testContext.Monitor.WriteGlobalLog (ot);
				if (!string.IsNullOrEmpty (et)) {
					testContext.Monitor.WriteGlobalLog ("ERROR:\n");
					testContext.Monitor.WriteGlobalLog (et);
				}
				testContext.Monitor.ReportRuntimeError ("Test execution failed.\n" + ot + "\n" + et, ex);
				return UnitTestResult.CreateIgnored ("Test execution failed");
			} finally {
				File.Delete (outFile);
				cons.Dispose ();
			}
		}
		UnitTestResult RunWithConsoleRunner (ProcessExecutionCommand cmd, UnitTest test, string suiteName, string pathName, string testName, TestContext testContext)
		{
			var outFile = Path.GetTempFileName ();
			LocalConsole cons = new LocalConsole ();

			try {
				LocalTestMonitor localMonitor = new LocalTestMonitor (testContext, test, suiteName, testName != null);

				if (!string.IsNullOrEmpty (cmd.Arguments))
					cmd.Arguments += " ";
				cmd.Arguments += "\"-xml=" + outFile + "\" " + AssemblyPath;

				bool automaticUpdates = cmd.Command.Contains ("GuiUnit") || (cmd.Command.Contains ("mdtool.exe") && cmd.Arguments.Contains ("run-md-tests"));
				if (!string.IsNullOrEmpty (testName))
					cmd.Arguments += " -run=" + suiteName + "." + testName;
				else if (!string.IsNullOrEmpty (suiteName))
					cmd.Arguments += " -run=" + suiteName;
				if (automaticUpdates) {
					var tcpListener = new MonoDevelop.NUnit.External.TcpTestListener (localMonitor);
					cmd.Arguments += " -port=" + tcpListener.Port;
				}
				var p = testContext.ExecutionContext.Execute (cmd, cons);

				testContext.Monitor.CancelRequested += p.Cancel;
				if (testContext.Monitor.IsCancelRequested)
					p.Cancel ();
				p.WaitForCompleted ();
				
				if (new FileInfo (outFile).Length == 0)
					throw new Exception ("Command failed");
				
				XDocument doc = XDocument.Load (outFile);

				if (doc.Root != null) {
					if (automaticUpdates) {
						DispatchService.GuiDispatch (delegate {
							testContext.ResultsPad.InitializeTestRun (test);
						});
					}

					var root = doc.Root.Elements ("test-suite").FirstOrDefault ();
					if (root != null) {
						cons.SetDone ();
						var ot = cons.Out.ReadToEnd ();
						var et = cons.Error.ReadToEnd ();
						testContext.Monitor.WriteGlobalLog (ot);
						if (!string.IsNullOrEmpty (et)) {
							testContext.Monitor.WriteGlobalLog ("ERROR:\n");
							testContext.Monitor.WriteGlobalLog (et);
						}

						bool macunitStyle = doc.Root.Element ("environment") != null && doc.Root.Element ("environment").Attribute ("macunit-version") != null;
						return ReportXmlResult (localMonitor, root, "", macunitStyle);
					}
				}
				throw new Exception ("Test results could not be parsed.");
			} catch (Exception ex) {
				cons.SetDone ();
				var ot = cons.Out.ReadToEnd ();
				var et = cons.Error.ReadToEnd ();
				testContext.Monitor.WriteGlobalLog (ot);
				if (!string.IsNullOrEmpty (et)) {
					testContext.Monitor.WriteGlobalLog ("ERROR:\n");
					testContext.Monitor.WriteGlobalLog (et);
				}
				testContext.Monitor.ReportRuntimeError ("Test execution failed.\n" + ot + "\n" + et, ex);
				return UnitTestResult.CreateIgnored ("Test execution failed");
			} finally {
				File.Delete (outFile);
			}
		}
		UnitTestResult RunWithConsoleRunner (ProcessExecutionCommand cmd, UnitTest test, string suiteName, string pathName, string testName, TestContext testContext)
		{
			var outFile = Path.GetTempFileName ();
			LocalConsole cons = new LocalConsole ();

			try {
				if (!string.IsNullOrEmpty (cmd.Arguments))
					cmd.Arguments += " ";
				cmd.Arguments += "\"-xml=" + outFile + "\" " + AssemblyPath;
				if (!string.IsNullOrEmpty (testName))
					cmd.Arguments += " -run=" + suiteName + "." + testName;
				else if (!string.IsNullOrEmpty (suiteName))
					cmd.Arguments += " -run=" + suiteName;
				var p = testContext.ExecutionContext.Execute (cmd, cons);

				testContext.Monitor.CancelRequested += p.Cancel;
				if (testContext.Monitor.IsCancelRequested)
					p.Cancel ();
				p.WaitForCompleted ();
				
				if (new FileInfo (outFile).Length == 0)
					throw new Exception ("Command failed");

				LocalTestMonitor localMonitor = new LocalTestMonitor (testContext, test, suiteName, testName != null);
				XDocument doc = XDocument.Load (outFile);
				if (doc.Root != null) {
					var root = doc.Root.Elements ("test-suite").FirstOrDefault ();
					if (root != null) {
						cons.SetDone ();
						var ot = cons.Out.ReadToEnd ();
						var et = cons.Error.ReadToEnd ();
						testContext.Monitor.WriteGlobalLog (ot);
						if (!string.IsNullOrEmpty (et)) {
							testContext.Monitor.WriteGlobalLog ("ERROR:\n");
							testContext.Monitor.WriteGlobalLog (et);
						}
						return ReportXmlResult (localMonitor, root, "");
					}
				}
				throw new Exception ("Test results could not be parsed.");
			} catch (Exception ex) {
				cons.SetDone ();
				var ot = cons.Out.ReadToEnd ();
				var et = cons.Error.ReadToEnd ();
				testContext.Monitor.WriteGlobalLog (ot);
				if (!string.IsNullOrEmpty (et)) {
					testContext.Monitor.WriteGlobalLog ("ERROR:\n");
					testContext.Monitor.WriteGlobalLog (et);
				}
				testContext.Monitor.ReportRuntimeError ("Test execution failed.\n" + ot + "\n" + et, ex);
				return UnitTestResult.CreateIgnored ("Test execution failed");
			} finally {
				File.Delete (outFile);
			}
		}