From dc76823be9ef89ff80a6491decec50d19de03375 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Mon, 10 Sep 2012 01:33:20 +0200 Subject: [PATCH] Implemented test runner. --- .../UnitTesting/Frameworks/SDTestService.cs | 12 +++- .../UnitTesting/Model/ITestProject.cs | 4 +- .../UnitTesting/Model/TestNamespace.cs | 2 +- .../UnitTesting/Model/TestProjectBase.cs | 3 +- .../NUnit/NUnitConsoleApplication.cs | 40 +++++------ .../UnitTesting/NUnit/NUnitTestMethod.cs | 13 ++++ .../UnitTesting/NUnit/NUnitTestProject.cs | 43 +++++++++++- .../UnitTesting/NUnit/NUnitTestRunner.cs | 10 +-- .../{TreeView => Pad}/ITestTreeView.cs | 0 .../{TreeView => Pad}/TestTreeView.cs | 0 .../{TreeView => Pad}/UnitTestNode.cs | 0 .../Analysis/UnitTesting/Pad/UnitTestsPad.cs | 5 +- .../ITestResultsMonitor.cs | 0 .../UnitTesting/TestRunner/ITestRunner.cs | 8 ++- .../TestExecutionManager.cs | 66 +++++++++++++++++-- .../TestExecutionOptions.cs | 0 .../TestRunner/TestProcessRunnerBase.cs | 27 ++------ .../UnitTesting/TestRunner/TestRunnerBase.cs | 28 ++++++-- .../Analysis/UnitTesting/UnitTesting.csproj | 25 +++++-- .../Src/Gui/Dialogs/AsynchronousWaitDialog.cs | 5 ++ .../Base/Project/Src/Gui/IProgressMonitor.cs | 7 +- .../Base/Project/Src/Gui/ProgressCollector.cs | 5 ++ 22 files changed, 224 insertions(+), 79 deletions(-) rename src/AddIns/Analysis/UnitTesting/{TreeView => Pad}/ITestTreeView.cs (100%) rename src/AddIns/Analysis/UnitTesting/{TreeView => Pad}/TestTreeView.cs (100%) rename src/AddIns/Analysis/UnitTesting/{TreeView => Pad}/UnitTestNode.cs (100%) rename src/AddIns/Analysis/UnitTesting/{Frameworks => TestRunner}/ITestResultsMonitor.cs (100%) rename src/AddIns/Analysis/UnitTesting/{Frameworks => TestRunner}/TestExecutionManager.cs (70%) rename src/AddIns/Analysis/UnitTesting/{Frameworks => TestRunner}/TestExecutionOptions.cs (100%) diff --git a/src/AddIns/Analysis/UnitTesting/Frameworks/SDTestService.cs b/src/AddIns/Analysis/UnitTesting/Frameworks/SDTestService.cs index 28577dd38c..4ee66fde37 100644 --- a/src/AddIns/Analysis/UnitTesting/Frameworks/SDTestService.cs +++ b/src/AddIns/Analysis/UnitTesting/Frameworks/SDTestService.cs @@ -68,12 +68,20 @@ namespace ICSharpCode.UnitTesting get { return runTestsCancellationTokenSource != null; } } - public Task RunTestsAsync(IEnumerable selectedTests, TestExecutionOptions options) + public async Task RunTestsAsync(IEnumerable selectedTests, TestExecutionOptions options) { CancelRunningTests(); runTestsCancellationTokenSource = new CancellationTokenSource(); + // invalidate commands as IsRunningTests changes + System.Windows.Input.CommandManager.InvalidateRequerySuggested(); var executionManager = new TestExecutionManager(); - return executionManager.RunTestsAsync(selectedTests, options, runTestsCancellationTokenSource.Token); + try { + await executionManager.RunTestsAsync(selectedTests, options, runTestsCancellationTokenSource.Token); + } finally { + runTestsCancellationTokenSource = null; + // invalidate commands as IsRunningTests changes + System.Windows.Input.CommandManager.InvalidateRequerySuggested(); + } } public void CancelRunningTests() diff --git a/src/AddIns/Analysis/UnitTesting/Model/ITestProject.cs b/src/AddIns/Analysis/UnitTesting/Model/ITestProject.cs index d297511f89..30984b24fc 100644 --- a/src/AddIns/Analysis/UnitTesting/Model/ITestProject.cs +++ b/src/AddIns/Analysis/UnitTesting/Model/ITestProject.cs @@ -42,6 +42,8 @@ namespace ICSharpCode.UnitTesting /// /// Runs the specified tests. The specified tests must belong to this project. /// - Task RunTestsAsync(IEnumerable tests, TestExecutionOptions options, IProgressMonitor progressMonitor); + ITestRunner CreateTestRunner(TestExecutionOptions options); + + void UpdateTestResult(TestResult result); } } diff --git a/src/AddIns/Analysis/UnitTesting/Model/TestNamespace.cs b/src/AddIns/Analysis/UnitTesting/Model/TestNamespace.cs index eb8a4cd4f7..4c0fe4d43e 100644 --- a/src/AddIns/Analysis/UnitTesting/Model/TestNamespace.cs +++ b/src/AddIns/Analysis/UnitTesting/Model/TestNamespace.cs @@ -26,7 +26,7 @@ namespace ICSharpCode.UnitTesting if (displayName != null) { this.displayName = displayName; } else { - this.displayName = namespaceName.Substring(namespaceName.IndexOf('.') + 1); + this.displayName = namespaceName.Substring(namespaceName.LastIndexOf('.') + 1); } BindResultToCompositeResultOfNestedTests(); } diff --git a/src/AddIns/Analysis/UnitTesting/Model/TestProjectBase.cs b/src/AddIns/Analysis/UnitTesting/Model/TestProjectBase.cs index 3065bac016..e2f3bc2f9e 100644 --- a/src/AddIns/Analysis/UnitTesting/Model/TestProjectBase.cs +++ b/src/AddIns/Analysis/UnitTesting/Model/TestProjectBase.cs @@ -33,8 +33,9 @@ namespace ICSharpCode.UnitTesting BindResultToCompositeResultOfNestedTests(); } - public abstract Task RunTestsAsync(IEnumerable tests, TestExecutionOptions options, IProgressMonitor progressMonitor); + public abstract ITestRunner CreateTestRunner(TestExecutionOptions options); public abstract ITest GetTestForEntity(IEntity entity); + public abstract void UpdateTestResult(TestResult result); // Test class management methods public abstract bool IsTestClass(ITypeDefinition typeDefinition); diff --git a/src/AddIns/Analysis/UnitTesting/NUnit/NUnitConsoleApplication.cs b/src/AddIns/Analysis/UnitTesting/NUnit/NUnitConsoleApplication.cs index 7e875f5528..aadaf8b64c 100644 --- a/src/AddIns/Analysis/UnitTesting/NUnit/NUnitConsoleApplication.cs +++ b/src/AddIns/Analysis/UnitTesting/NUnit/NUnitConsoleApplication.cs @@ -5,8 +5,8 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Text; - using ICSharpCode.Core; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Gui; @@ -16,34 +16,33 @@ namespace ICSharpCode.UnitTesting { public class NUnitConsoleApplication { - /* - public NUnitConsoleApplication(ITestProject project, IEnumerable selectedTests, UnitTestingOptions options) + public NUnitConsoleApplication(IEnumerable selectedTests, UnitTestingOptions options) { - Initialize(project, selectedTests); + Initialize(selectedTests); InitializeOptions(options); } - public NUnitConsoleApplication(ITestProject project, IEnumerable selectedTests) + public NUnitConsoleApplication(IEnumerable selectedTests) { - Initialize(project, selectedTests); + Initialize(selectedTests); } - void Initialize(ITestProject project, IEnumerable selectedTests) + void Initialize(IEnumerable selectedTests) { - this.selectedTests = selectedTests; - this.project = selectedTests.Project; + ITest test = selectedTests.Single(); + this.project = test.ParentProject.Project; Assemblies.Add(project.OutputAssemblyFullPath); - if (selectedTests.NamespaceFilter != null) { - NamespaceFilter = selectedTests.NamespaceFilter; - } - if (selectedTests.Class != null) { - Fixture = selectedTests.Class.QualifiedName; - if (selectedTests.Member != null) { - Test = selectedTests.Member.Member.Name; - } + if (test is TestNamespace) { + NamespaceFilter = ((TestNamespace)test).NamespaceName; + } else if (test is NUnitTestClass) { + var testClass = (NUnitTestClass)test; + Fixture = testClass.ReflectionName; + } else if (test is NUnitTestMethod) { + var testMethod = (NUnitTestMethod)test; + Fixture = testMethod.FixtureReflectionName; + Test = testMethod.Name; } } - */ void InitializeOptions(UnitTestingOptions options) { @@ -152,11 +151,6 @@ namespace ICSharpCode.UnitTesting public string NamespaceFilter; IProject project; - IEnumerable selectedTests; - - public IEnumerable SelectedTests { - get { return selectedTests; } - } public IProject Project { get { return project; } diff --git a/src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestMethod.cs b/src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestMethod.cs index 7909fcae6f..93a9eb4980 100644 --- a/src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestMethod.cs +++ b/src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestMethod.cs @@ -31,5 +31,18 @@ namespace ICSharpCode.UnitTesting public override string DisplayName { get { return method.Name; } } + + public string Name { + get { return method.Name; } + } + + public string FixtureReflectionName { + get { return method.DeclaringTypeDefinition.ReflectionName; } + } + + public void UpdateTestResult(TestResult result) + { + this.Result = result.ResultType; + } } } diff --git a/src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestProject.cs b/src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestProject.cs index c3a9af304d..db6e625503 100644 --- a/src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestProject.cs +++ b/src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestProject.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem.Implementation; @@ -20,9 +21,12 @@ namespace ICSharpCode.UnitTesting { } - public override Task RunTestsAsync(IEnumerable tests, TestExecutionOptions options, IProgressMonitor progressMonitor) + public override ITestRunner CreateTestRunner(TestExecutionOptions options) { - throw new NotImplementedException(); + if (options.UseDebugger) + return new NUnitTestDebugger(); + else + return new NUnitTestRunner(); } public override void UpdateTestClass(ITest test, ITypeDefinition typeDefinition) @@ -56,5 +60,40 @@ namespace ICSharpCode.UnitTesting else return null; } + + public override void UpdateTestResult(TestResult result) + { + int pos = result.Name.LastIndexOf('.'); + if (pos < 0) + return; + string fixtureName = result.Name.Substring(0, pos); + string methodName = result.Name.Substring(pos + 1); + var testClass = FindTestClass(fixtureName); + if (testClass != null) { + var testMethod = testClass.NestedTests.OfType().FirstOrDefault(m => m.Name == methodName); + if (testMethod != null) { + testMethod.UpdateTestResult(result); + } + } + } + + NUnitTestClass FindTestClass(string fixtureName) + { + ITypeReference r = ReflectionHelper.ParseReflectionName(fixtureName); + return FindTestClass(r); + } + + NUnitTestClass FindTestClass(ITypeReference r) + { + var gctr = r as GetClassTypeReference; + if (gctr != null) { + return (NUnitTestClass)GetTestClass(new FullNameAndTypeParameterCount(gctr.Namespace, gctr.Name, gctr.TypeParameterCount)); + } + var ntc = r as NestedTypeReference; + if (ntc != null) { + + } + return null; + } } } diff --git a/src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestRunner.cs b/src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestRunner.cs index 9d35baae13..cecc5eb4e4 100644 --- a/src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestRunner.cs +++ b/src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestRunner.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; using System.Diagnostics; - +using System.Linq; +using System.Threading.Tasks; +using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Util; namespace ICSharpCode.UnitTesting @@ -14,8 +16,8 @@ namespace ICSharpCode.UnitTesting UnitTestingOptions options; public NUnitTestRunner() - : this(new TestProcessRunnerBaseContext(), - UnitTestingOptions.Instance.Clone()) + : this(new TestProcessRunnerBaseContext(), + UnitTestingOptions.Instance.Clone()) { } @@ -24,7 +26,7 @@ namespace ICSharpCode.UnitTesting { this.options = options; } - + protected override ProcessStartInfo GetProcessStartInfo(IEnumerable selectedTests) { NUnitConsoleApplication app = new NUnitConsoleApplication(selectedTests, options); diff --git a/src/AddIns/Analysis/UnitTesting/TreeView/ITestTreeView.cs b/src/AddIns/Analysis/UnitTesting/Pad/ITestTreeView.cs similarity index 100% rename from src/AddIns/Analysis/UnitTesting/TreeView/ITestTreeView.cs rename to src/AddIns/Analysis/UnitTesting/Pad/ITestTreeView.cs diff --git a/src/AddIns/Analysis/UnitTesting/TreeView/TestTreeView.cs b/src/AddIns/Analysis/UnitTesting/Pad/TestTreeView.cs similarity index 100% rename from src/AddIns/Analysis/UnitTesting/TreeView/TestTreeView.cs rename to src/AddIns/Analysis/UnitTesting/Pad/TestTreeView.cs diff --git a/src/AddIns/Analysis/UnitTesting/TreeView/UnitTestNode.cs b/src/AddIns/Analysis/UnitTesting/Pad/UnitTestNode.cs similarity index 100% rename from src/AddIns/Analysis/UnitTesting/TreeView/UnitTestNode.cs rename to src/AddIns/Analysis/UnitTesting/Pad/UnitTestNode.cs diff --git a/src/AddIns/Analysis/UnitTesting/Pad/UnitTestsPad.cs b/src/AddIns/Analysis/UnitTesting/Pad/UnitTestsPad.cs index c06a55a7cd..7a85294d1f 100644 --- a/src/AddIns/Analysis/UnitTesting/Pad/UnitTestsPad.cs +++ b/src/AddIns/Analysis/UnitTesting/Pad/UnitTestsPad.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Windows.Controls; using System.Windows.Media.Imaging; @@ -35,12 +36,12 @@ namespace ICSharpCode.UnitTesting this.testService = testService; panel = new DockPanel(); + treeView = new TestTreeView(); // treeView must be created first because it's used by CreateToolBar toolBar = CreateToolBar("/SharpDevelop/Pads/UnitTestsPad/Toolbar"); panel.Children.Add(toolBar); DockPanel.SetDock(toolBar, Dock.Top); - treeView = new TestTreeView(); panel.Children.Add(treeView); treeView.ContextMenu = CreateContextMenu("/SharpDevelop/Pads/UnitTestsPad/ContextMenu"); @@ -70,6 +71,7 @@ namespace ICSharpCode.UnitTesting /// protected virtual ToolBar CreateToolBar(string name) { + Debug.Assert(treeView != null); return ToolBarService.CreateToolBar(treeView, treeView, name); } @@ -79,6 +81,7 @@ namespace ICSharpCode.UnitTesting /// protected virtual ContextMenu CreateContextMenu(string name) { + Debug.Assert(treeView != null); return MenuService.CreateContextMenu(treeView, name); } } diff --git a/src/AddIns/Analysis/UnitTesting/Frameworks/ITestResultsMonitor.cs b/src/AddIns/Analysis/UnitTesting/TestRunner/ITestResultsMonitor.cs similarity index 100% rename from src/AddIns/Analysis/UnitTesting/Frameworks/ITestResultsMonitor.cs rename to src/AddIns/Analysis/UnitTesting/TestRunner/ITestResultsMonitor.cs diff --git a/src/AddIns/Analysis/UnitTesting/TestRunner/ITestRunner.cs b/src/AddIns/Analysis/UnitTesting/TestRunner/ITestRunner.cs index 8a29324c5e..a94da5326b 100644 --- a/src/AddIns/Analysis/UnitTesting/TestRunner/ITestRunner.cs +++ b/src/AddIns/Analysis/UnitTesting/TestRunner/ITestRunner.cs @@ -3,6 +3,9 @@ using System; using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Util; namespace ICSharpCode.UnitTesting @@ -10,9 +13,8 @@ namespace ICSharpCode.UnitTesting public interface ITestRunner : IDisposable { event EventHandler TestFinished; - event EventHandler AllTestsFinished; event EventHandler MessageReceived; - void Start(IEnumerable selectedTests); - void Stop(); + + Task RunAsync(IEnumerable selectedTests, IProgress progress, CancellationToken cancellationToken); } } diff --git a/src/AddIns/Analysis/UnitTesting/Frameworks/TestExecutionManager.cs b/src/AddIns/Analysis/UnitTesting/TestRunner/TestExecutionManager.cs similarity index 70% rename from src/AddIns/Analysis/UnitTesting/Frameworks/TestExecutionManager.cs rename to src/AddIns/Analysis/UnitTesting/TestRunner/TestExecutionManager.cs index f5c5db984c..701064bf73 100644 --- a/src/AddIns/Analysis/UnitTesting/Frameworks/TestExecutionManager.cs +++ b/src/AddIns/Analysis/UnitTesting/TestRunner/TestExecutionManager.cs @@ -27,6 +27,7 @@ namespace ICSharpCode.UnitTesting.Frameworks readonly IUnitTestSaveAllFilesCommand saveAllFilesCommand; readonly ITestService testService; readonly IWorkbench workbench; + readonly IMessageLoop mainThread; readonly IStatusBarService statusBarService; readonly IBuildOptions buildOptions; @@ -38,11 +39,14 @@ namespace ICSharpCode.UnitTesting.Frameworks this.testService = SD.GetRequiredService(); this.workbench = SD.Workbench; this.statusBarService = SD.StatusBar; + this.mainThread = SD.MainThread; this.buildOptions = new UnitTestBuildOptions(); } readonly MultiDictionary testsByProject = new MultiDictionary(); CancellationToken cancellationToken; + ITestProject currentProjectBeingTested; + IProgressMonitor testProgressMonitor; public async Task RunTestsAsync(IEnumerable selectedTests, TestExecutionOptions options, CancellationToken cancellationToken) { @@ -69,11 +73,15 @@ namespace ICSharpCode.UnitTesting.Frameworks using (IProgressMonitor progressMonitor = statusBarService.CreateProgressMonitor(cancellationToken)) { int projectsLeftToRun = testsByProject.Count; foreach (IGrouping g in testsByProject) { - ITestProject project = g.Key; - progressMonitor.TaskName = GetProgressMonitorLabel(project); + currentProjectBeingTested = g.Key; + progressMonitor.TaskName = GetProgressMonitorLabel(currentProjectBeingTested); progressMonitor.Progress = GetProgress(projectsLeftToRun); - using (IProgressMonitor nested = progressMonitor.CreateSubTask(1.0 / testsByProject.Count)) { - await project.RunTestsAsync(g, options, nested); + using (testProgressMonitor = progressMonitor.CreateSubTask(1.0 / testsByProject.Count)) { + using (ITestRunner testRunner = currentProjectBeingTested.CreateTestRunner(options)) { + testRunner.MessageReceived += testRunner_MessageReceived; + testRunner.TestFinished += testRunner_TestFinished; + await testRunner.RunAsync(g, testProgressMonitor, testProgressMonitor.CancellationToken); + } } projectsLeftToRun--; progressMonitor.CancellationToken.ThrowIfCancellationRequested(); @@ -82,7 +90,7 @@ namespace ICSharpCode.UnitTesting.Frameworks ShowErrorList(); } - + void GroupTestsByProject(IEnumerable selectedTests) { foreach (ITest test in selectedTests) { @@ -139,6 +147,54 @@ namespace ICSharpCode.UnitTesting.Frameworks return (double)(totalProjectCount - projectsLeftToRunCount) / totalProjectCount; } + void testRunner_MessageReceived(object sender, MessageReceivedEventArgs e) + { + testService.UnitTestMessageView.AppendLine(e.Message); + } + + void testRunner_TestFinished(object sender, TestFinishedEventArgs e) + { + mainThread.InvokeAsync(delegate { ShowResult(e.Result); }).FireAndForget(); + } + + protected void ShowResult(TestResult result) + { + if (IsTestResultFailureOrIsIgnored(result)) { + AddTaskForTestResult(result); + UpdateProgressMonitorStatus(result); + } + UpdateTestResult(result); + } + + bool IsTestResultFailureOrIsIgnored(TestResult result) + { + return result.IsFailure || result.IsIgnored; + } + + void AddTaskForTestResult(TestResult testResult) + { + SDTask task = TestResultTask.Create(testResult, currentProjectBeingTested); + taskService.Add(task); + } + + void UpdateProgressMonitorStatus(TestResult result) + { + if (testProgressMonitor != null) { + if (result.IsFailure) { + testProgressMonitor.Status = OperationStatus.Error; + } else if (result.IsIgnored && testProgressMonitor.Status == OperationStatus.Normal) { + testProgressMonitor.Status = OperationStatus.Warning; + } + } + } + + void UpdateTestResult(TestResult result) + { + if (currentProjectBeingTested != null) { + currentProjectBeingTested.UpdateTestResult(result); + } + } + void ShowErrorList() { if (taskService.SomethingWentWrong && buildOptions.ShowErrorListAfterBuild) { diff --git a/src/AddIns/Analysis/UnitTesting/Frameworks/TestExecutionOptions.cs b/src/AddIns/Analysis/UnitTesting/TestRunner/TestExecutionOptions.cs similarity index 100% rename from src/AddIns/Analysis/UnitTesting/Frameworks/TestExecutionOptions.cs rename to src/AddIns/Analysis/UnitTesting/TestRunner/TestExecutionOptions.cs diff --git a/src/AddIns/Analysis/UnitTesting/TestRunner/TestProcessRunnerBase.cs b/src/AddIns/Analysis/UnitTesting/TestRunner/TestProcessRunnerBase.cs index 71ded442a7..9595482b47 100644 --- a/src/AddIns/Analysis/UnitTesting/TestRunner/TestProcessRunnerBase.cs +++ b/src/AddIns/Analysis/UnitTesting/TestRunner/TestProcessRunnerBase.cs @@ -18,31 +18,12 @@ namespace ICSharpCode.UnitTesting IFileSystem fileSystem; IMessageService messageService; - public TestProcessRunnerBase() - : this(new UnitTestProcessRunner(), - new TestResultsMonitor(), - new UnitTestFileService(), - SD.MessageService) - { - } - public TestProcessRunnerBase(TestProcessRunnerBaseContext context) - : this(context.TestProcessRunner, - context.TestResultsMonitor, - context.FileSystem, - context.MessageService) - { - } - - public TestProcessRunnerBase(IUnitTestProcessRunner processRunner, - ITestResultsMonitor testResultsMonitor, - IFileSystem fileSystem, - IMessageService messageService) { - this.processRunner = processRunner; - this.testResultsMonitor = testResultsMonitor; - this.fileSystem = fileSystem; - this.messageService = messageService; + this.processRunner = context.TestProcessRunner; + this.testResultsMonitor = context.TestResultsMonitor; + this.fileSystem = context.FileSystem; + this.messageService = context.MessageService; processRunner.LogStandardOutputAndError = false; processRunner.OutputLineReceived += OutputLineReceived; diff --git a/src/AddIns/Analysis/UnitTesting/TestRunner/TestRunnerBase.cs b/src/AddIns/Analysis/UnitTesting/TestRunner/TestRunnerBase.cs index 1ee17d65d2..2a4352d5c6 100644 --- a/src/AddIns/Analysis/UnitTesting/TestRunner/TestRunnerBase.cs +++ b/src/AddIns/Analysis/UnitTesting/TestRunner/TestRunnerBase.cs @@ -4,13 +4,29 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; namespace ICSharpCode.UnitTesting { public abstract class TestRunnerBase : ITestRunner { - public TestRunnerBase() + TaskCompletionSource tcs; + CancellationTokenRegistration cancellationTokenRegistration; + bool wasCancelled; + + public Task RunAsync(IEnumerable selectedTests, IProgress progress, CancellationToken cancellationToken) + { + tcs = new TaskCompletionSource(); + Start(selectedTests); + cancellationTokenRegistration = cancellationToken.Register(Cancel, true); + return tcs.Task; + } + + void Cancel() { + wasCancelled = true; + Stop(); } protected virtual ProcessStartInfo GetProcessStartInfo(IEnumerable selectedTests) @@ -29,13 +45,13 @@ namespace ICSharpCode.UnitTesting return String.Format("\"{0}\" {1}", startInfo.FileName, startInfo.Arguments); } - public event EventHandler AllTestsFinished; - protected void OnAllTestsFinished(object source, EventArgs e) { - if (AllTestsFinished != null) { - AllTestsFinished(source, e); - } + cancellationTokenRegistration.Dispose(); + if (wasCancelled) + tcs.SetCanceled(); + else + tcs.SetResult(e); } public event EventHandler TestFinished; diff --git a/src/AddIns/Analysis/UnitTesting/UnitTesting.csproj b/src/AddIns/Analysis/UnitTesting/UnitTesting.csproj index a068bc35cd..3eede71d50 100644 --- a/src/AddIns/Analysis/UnitTesting/UnitTesting.csproj +++ b/src/AddIns/Analysis/UnitTesting/UnitTesting.csproj @@ -71,8 +71,6 @@ - - @@ -93,8 +91,13 @@ + + + + + @@ -105,9 +108,19 @@ - - - + + + + + + + + + + + + + @@ -174,7 +187,7 @@ - + diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/AsynchronousWaitDialog.cs b/src/Main/Base/Project/Src/Gui/Dialogs/AsynchronousWaitDialog.cs index 7b1967d2ea..120eefb6b9 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/AsynchronousWaitDialog.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/AsynchronousWaitDialog.cs @@ -288,6 +288,11 @@ namespace ICSharpCode.SharpDevelop.Gui set { collector.ProgressMonitor.Progress = value; } } + void IProgress.Report(double value) + { + this.Progress = value; + } + /// public bool ShowingDialog { get { return collector.ProgressMonitor.ShowingDialog; } diff --git a/src/Main/Base/Project/Src/Gui/IProgressMonitor.cs b/src/Main/Base/Project/Src/Gui/IProgressMonitor.cs index a6a3ff7e51..c7959b6335 100644 --- a/src/Main/Base/Project/Src/Gui/IProgressMonitor.cs +++ b/src/Main/Base/Project/Src/Gui/IProgressMonitor.cs @@ -17,7 +17,7 @@ namespace ICSharpCode.SharpDevelop.Gui /// automatically sent to the correct GUI thread. /// Using a progress monitor from multiple threads is possible if the user synchronizes the access. /// - public interface IProgressMonitor : IDisposable + public interface IProgressMonitor : IDisposable, IProgress { /// /// Gets/Sets the amount of work already done within this task. @@ -115,6 +115,11 @@ namespace ICSharpCode.SharpDevelop.Gui return new DummyProgressMonitor() { CancellationToken = cancellationToken }; } + void IProgress.Report(double value) + { + this.Progress = value; + } + public void Dispose() { } diff --git a/src/Main/Base/Project/Src/Gui/ProgressCollector.cs b/src/Main/Base/Project/Src/Gui/ProgressCollector.cs index 5ea0824838..a2e2de7c57 100644 --- a/src/Main/Base/Project/Src/Gui/ProgressCollector.cs +++ b/src/Main/Base/Project/Src/Gui/ProgressCollector.cs @@ -266,6 +266,11 @@ namespace ICSharpCode.SharpDevelop.Gui } } + void IProgress.Report(double value) + { + this.Progress = value; + } + void UpdateProgress(double progress) { if (parent != null)