Browse Source

[WIP] Major refactoring of the unit testing addin:

A lot of functionality gets moved from the main portion of the AddIn into the framework-specific providers.

We no longer deal with test classes and members, but instead use the new ITest interface.
A test can be a whole project, namespace, class, or just a single method.
This can be used to support features like the NUnit [TestCase] attribute, where a single method might result in multiple tests.
newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
dff21e821f
  1. 398
      src/AddIns/Analysis/UnitTesting/Commands/AbstractRunTestCommand.cs
  2. 25
      src/AddIns/Analysis/UnitTesting/Commands/IRunTestCommandContext.cs
  3. 56
      src/AddIns/Analysis/UnitTesting/Commands/PadCommands.cs
  4. 26
      src/AddIns/Analysis/UnitTesting/Commands/RunAllTestsInPadCommand.cs
  5. 42
      src/AddIns/Analysis/UnitTesting/Commands/RunProjectTestsInPadCommand.cs
  6. 68
      src/AddIns/Analysis/UnitTesting/Commands/RunTestCommandContext.cs
  7. 26
      src/AddIns/Analysis/UnitTesting/Commands/RunTestInPadCommand.cs
  8. 26
      src/AddIns/Analysis/UnitTesting/Commands/RunTestWithDebuggerCommand.cs
  9. 4
      src/AddIns/Analysis/UnitTesting/Commands/RunningTestsCondition.cs
  10. 88
      src/AddIns/Analysis/UnitTesting/Commands/TestableCondition.cs
  11. 70
      src/AddIns/Analysis/UnitTesting/Commands/UnitTestCommands.cs
  12. 23
      src/AddIns/Analysis/UnitTesting/Frameworks/IRegisteredTestFrameworks.cs
  13. 14
      src/AddIns/Analysis/UnitTesting/Frameworks/ITestFramework.cs
  14. 12
      src/AddIns/Analysis/UnitTesting/Frameworks/ITestFrameworkFactory.cs
  15. 51
      src/AddIns/Analysis/UnitTesting/Frameworks/ITestService.cs
  16. 99
      src/AddIns/Analysis/UnitTesting/Frameworks/RegisteredTestFrameworks.cs
  17. 88
      src/AddIns/Analysis/UnitTesting/Frameworks/SDTestService.cs
  18. 149
      src/AddIns/Analysis/UnitTesting/Frameworks/TestExecutionManager.cs
  19. 19
      src/AddIns/Analysis/UnitTesting/Frameworks/TestExecutionOptions.cs
  20. 8
      src/AddIns/Analysis/UnitTesting/Frameworks/TestFrameworkDescriptor.cs
  21. 7
      src/AddIns/Analysis/UnitTesting/Frameworks/TestFrameworkDoozer.cs
  22. 23
      src/AddIns/Analysis/UnitTesting/Frameworks/TestFrameworkFactory.cs
  23. 57
      src/AddIns/Analysis/UnitTesting/Frameworks/TestService.cs
  24. 2
      src/AddIns/Analysis/UnitTesting/Interfaces/IBuildProjectFactory.cs
  25. 1
      src/AddIns/Analysis/UnitTesting/Interfaces/IUnitTestTaskService.cs
  26. 15
      src/AddIns/Analysis/UnitTesting/Interfaces/IUnitTestWorkbench.cs
  27. 2
      src/AddIns/Analysis/UnitTesting/Interfaces/UnitTestBuildProjectFactory.cs
  28. 5
      src/AddIns/Analysis/UnitTesting/Interfaces/UnitTestTaskService.cs
  29. 27
      src/AddIns/Analysis/UnitTesting/Interfaces/UnitTestWorkbench.cs
  30. 55
      src/AddIns/Analysis/UnitTesting/Model/ITest.cs
  31. 47
      src/AddIns/Analysis/UnitTesting/Model/ITestProject.cs
  32. 33
      src/AddIns/Analysis/UnitTesting/Model/ITestSolution.cs
  33. 143
      src/AddIns/Analysis/UnitTesting/Model/TestBase.cs
  34. 199
      src/AddIns/Analysis/UnitTesting/Model/TestCollection.cs
  35. 46
      src/AddIns/Analysis/UnitTesting/Model/TestNamespace.cs
  36. 58
      src/AddIns/Analysis/UnitTesting/Model/TestProjectBase.cs
  37. 30
      src/AddIns/Analysis/UnitTesting/Model/TestResultTypeChangedEventArgs.cs
  38. 80
      src/AddIns/Analysis/UnitTesting/Model/TestSolution.cs
  39. 16
      src/AddIns/Analysis/UnitTesting/NUnit/NUnitConsoleApplication.cs
  40. 4
      src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestDebugger.cs
  41. 39
      src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestFramework.cs
  42. 26
      src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestProject.cs
  43. 4
      src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestRunner.cs
  44. 53
      src/AddIns/Analysis/UnitTesting/Pad/EmptyUnitTestsPad.cs
  45. 18
      src/AddIns/Analysis/UnitTesting/Pad/IUnitTestsPad.cs
  46. 236
      src/AddIns/Analysis/UnitTesting/Pad/UnitTestsPad.cs
  47. 3
      src/AddIns/Analysis/UnitTesting/TestRunner/ITestRunner.cs
  48. 91
      src/AddIns/Analysis/UnitTesting/TestRunner/SelectedTests.cs
  49. 4
      src/AddIns/Analysis/UnitTesting/TestRunner/TestDebuggerBase.cs
  50. 4
      src/AddIns/Analysis/UnitTesting/TestRunner/TestProcessRunnerBase.cs
  51. 4
      src/AddIns/Analysis/UnitTesting/TestRunner/TestResultTask.cs
  52. 5
      src/AddIns/Analysis/UnitTesting/TestRunner/TestRunnerBase.cs
  53. 2
      src/AddIns/Analysis/UnitTesting/TreeView/ClassUnitTestNode.cs
  54. 20
      src/AddIns/Analysis/UnitTesting/TreeView/ITestTreeView.cs
  55. 2
      src/AddIns/Analysis/UnitTesting/TreeView/MemberUnitTestNode.cs
  56. 8
      src/AddIns/Analysis/UnitTesting/TreeView/NamespaceUnitTestNode.cs
  57. 10
      src/AddIns/Analysis/UnitTesting/TreeView/ProjectUnitTestNode.cs
  58. 8
      src/AddIns/Analysis/UnitTesting/TreeView/RootUnitTestNode.cs
  59. 104
      src/AddIns/Analysis/UnitTesting/TreeView/TestTreeView.cs
  60. 38
      src/AddIns/Analysis/UnitTesting/TreeView/UnitTestBaseNode.cs
  61. 128
      src/AddIns/Analysis/UnitTesting/TreeView/UnitTestNode.cs
  62. 21
      src/AddIns/Analysis/UnitTesting/UnitTesting.addin
  63. 56
      src/AddIns/Analysis/UnitTesting/UnitTesting.csproj
  64. 20
      src/Libraries/NRefactory/ICSharpCode.NRefactory/Utils/MultiDictionary.cs
  65. 1
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  66. 23
      src/Main/Base/Project/Src/Commands/BuildCommands.cs
  67. 4
      src/Main/Base/Project/Src/Project/MultipleProjectBuildable.cs
  68. 22
      src/Main/Base/Project/Src/Services/Tasks/TaskService.cs

398
src/AddIns/Analysis/UnitTesting/Commands/AbstractRunTestCommand.cs

@ -1,398 +0,0 @@ @@ -1,398 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Project.Commands;
namespace ICSharpCode.UnitTesting
{
public abstract class AbstractRunTestCommand : AbstractMenuCommand
{
static AbstractRunTestCommand runningTestCommand;
IUnitTestsPad unitTestsPad;
SelectedTests selectedTests;
IRunTestCommandContext context;
ITestRunner testRunner;
IProgressMonitor testProgressMonitor;
int totalProjectCount;
public AbstractRunTestCommand()
: this(new RunTestCommandContext())
{
}
public AbstractRunTestCommand(IRunTestCommandContext context)
{
this.context = context;
}
protected IRunTestCommandContext Context {
get { return context; }
}
/// <summary>
/// Gets the running test command.
/// </summary>
public static AbstractRunTestCommand RunningTestCommand {
get { return runningTestCommand; }
set { runningTestCommand = value; }
}
/// <summary>
/// Gets whether a test is currently running.
/// </summary>
public static bool IsRunningTest {
get { return runningTestCommand != null; }
}
public override void Run()
{
GetUnitTestsPad();
selectedTests = GetSelectedTests();
if (selectedTests.HasProjects) {
runningTestCommand = this;
BeforeRun();
BuildAndRunTests();
}
}
SelectedTests GetSelectedTests()
{
return new SelectedTests(Owner, unitTestsPad.GetProjects());
}
void GetUnitTestsPad()
{
unitTestsPad = context.OpenUnitTestsPad;
if (unitTestsPad == null) {
unitTestsPad = CreateEmptyUnitTestsPad();
}
}
EmptyUnitTestsPad CreateEmptyUnitTestsPad()
{
return new EmptyUnitTestsPad(context.OpenSolution);
}
/// <summary>
/// Sets the initial workbench state before starting
/// a test run.
/// </summary>
void BeforeRun()
{
ClearTasks();
ClearUnitTestCategoryText();
ShowUnitTestsPad();
ShowOutputPad();
UpdateUnitTestsPadToolbar();
ResetAllTestResultsInUnitTestsPad();
OnBeforeBuild();
}
void BuildAndRunTests()
{
if (IsBuildNeededBeforeTestRun()) {
BuildProjectBeforeRunningTests(selectedTests);
} else {
context.SaveAllFilesCommand.SaveAllFiles();
RunTests(selectedTests);
}
}
bool IsBuildNeededBeforeTestRun()
{
return selectedTests.Projects.Any(p => context.RegisteredTestFrameworks.IsBuildNeededBeforeTestRunForProject(p));
}
void ClearTasks()
{
context.TaskService.BuildMessageViewCategory.ClearText();
context.TaskService.InUpdate = true;
context.TaskService.ClearExceptCommentTasks();
context.TaskService.InUpdate = false;
}
void ClearUnitTestCategoryText()
{
context.UnitTestCategory.ClearText();
}
void ShowUnitTestsPad()
{
unitTestsPad.BringToFront();
}
void StopProgressMonitor()
{
if (testProgressMonitor != null) {
testProgressMonitor.Dispose();
testProgressMonitor = null;
}
}
void UpdateUnitTestsPadToolbar()
{
unitTestsPad.UpdateToolbar();
}
/// <summary>
/// Called before the build is started (even if no build needs to be performed).
/// If multiple projects are to be tested this is called only once.
/// </summary>
protected virtual void OnBeforeBuild()
{
}
/// <summary>
/// Called before all tests are run (after the build has finished successfully).
/// If multiple projects are to be tested this is called only once.
/// </summary>
protected virtual void OnBeforeRunTests()
{
}
/// <summary>
/// Runs the tests after building the project(s) under test.
/// </summary>
void BuildProjectBeforeRunningTests(SelectedTests selectedTests)
{
BuildProject build = CreateBuildProjectBeforeTestRun(selectedTests);
build.BuildComplete += delegate {
OnBuildComplete(build.LastBuildResults, selectedTests);
};
build.Run();
}
BuildProject CreateBuildProjectBeforeTestRun(SelectedTests selectedTests)
{
IEnumerable<IProject> projects = GetProjectsRequiringBuildBeforeTestRun(selectedTests);
return context.BuildProjectFactory.CreateBuildProjectBeforeTestRun(projects);
}
IEnumerable<IProject> GetProjectsRequiringBuildBeforeTestRun(SelectedTests selectedTests)
{
return selectedTests
.Projects
.Where(p => context.RegisteredTestFrameworks.IsBuildNeededBeforeTestRunForProject(p));
}
/// <summary>
/// Stops running the tests.
/// </summary>
public void Stop()
{
StopActiveTestRunner();
runningTestCommand = null;
UpdateUnitTestsPadToolbar();
OnStop();
}
void StopActiveTestRunner()
{
if (testRunner != null) {
testRunner.Stop();
testRunner.Dispose();
testRunner = null;
}
}
/// <summary>
/// Called after all tests have been run even if there have
/// been errors. If multiple projects are to be tested this is called only once.
/// </summary>
protected virtual void OnAfterRunTests()
{
}
/// <summary>
/// Called by derived classes when a single test run
/// is finished.
/// </summary>
protected void TestRunCompleted()
{
StopActiveTestRunner();
selectedTests.RemoveFirstProject();
if (selectedTests.HasProjects) {
RunTests(selectedTests);
} else {
StopProgressMonitor();
runningTestCommand = null;
UpdateUnitTestsPadToolbar();
ShowErrorList();
OnAfterRunTests();
}
}
void TestFinished(object source, TestFinishedEventArgs e)
{
context.Workbench.SafeThreadAsyncCall(ShowResult, e.Result);
}
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)
{
TestProject project = GetTestProjectForProject(selectedTests.Project);
SDTask task = TestResultTask.Create(testResult, project);
context.TaskService.Add(task);
}
/// <summary>
/// Called when the test run should be stopped.
/// </summary>
protected virtual void OnStop()
{
}
void ShowOutputPad()
{
ShowPad(context.Workbench.GetPad(typeof(CompilerMessageView)));
}
protected void ShowPad(PadDescriptor padDescriptor)
{
context.Workbench.SafeThreadAsyncCall(padDescriptor.BringPadToFront);
}
void ShowErrorList()
{
if (HasErrorsThatShouldBeDisplayed()) {
ShowPad(context.Workbench.GetPad(typeof(ErrorListPad)));
}
}
bool HasErrorsThatShouldBeDisplayed()
{
return context.TaskService.SomethingWentWrong &&
context.BuildOptions.ShowErrorListAfterBuild;
}
/// <summary>
/// Runs the test for the project after a successful build.
/// </summary>
void OnBuildComplete(BuildResults results, SelectedTests selectedTests)
{
if (BuildHasNoErrorsAndStillRunningTests(results)) {
RunTests(selectedTests);
} else {
if (IsRunningTest) {
Stop();
}
ShowErrorList();
}
}
bool BuildHasNoErrorsAndStillRunningTests(BuildResults results)
{
return (results.ErrorCount == 0) && IsRunningTest;
}
void RunTests(SelectedTests selectedTests)
{
if (testProgressMonitor == null) {
OnBeforeRunTests();
testProgressMonitor = context.StatusBarService.CreateProgressMonitor();
totalProjectCount = selectedTests.ProjectsCount;
}
testProgressMonitor.TaskName = GetProgressMonitorLabel(selectedTests.Project);
testProgressMonitor.Progress = GetProgress(selectedTests.ProjectsCount);
testRunner = CreateTestRunner(selectedTests.Project);
if (testRunner != null) {
StartTestRunner();
}
}
void StartTestRunner()
{
testRunner.MessageReceived += TestRunnerMessageReceived;
testRunner.AllTestsFinished += AllTestsFinished;
testRunner.TestFinished += TestFinished;
testRunner.Start(selectedTests);
}
string GetProgressMonitorLabel(IProject project)
{
StringTagPair tagPair = new StringTagPair("Name", project.Name);
return StringParser.Parse("${res:ICSharpCode.UnitTesting.StatusBarProgressLabel}", tagPair);
}
double GetProgress(int projectsLeftToRunCount)
{
return (double)(totalProjectCount - projectsLeftToRunCount) / totalProjectCount;
}
protected virtual ITestRunner CreateTestRunner(IProject project)
{
return null;
}
protected virtual void TestRunnerMessageReceived(object source, MessageReceivedEventArgs e)
{
context.UnitTestCategory.AppendLine(e.Message);
}
void AllTestsFinished(object source, EventArgs e)
{
context.Workbench.SafeThreadAsyncCall(TestRunCompleted);
}
/// <summary>
/// Clears the test results in the test tree view for all the
/// displayed projects.
/// </summary>
void ResetAllTestResultsInUnitTestsPad()
{
unitTestsPad.ResetTestResults();
}
TestProject GetTestProjectForProject(IProject project)
{
return unitTestsPad.GetTestProject(project);
}
void UpdateTestResult(TestResult result)
{
TestProject testProject = GetTestProjectForProject(selectedTests.Project);
if (testProject != null) {
testProject.UpdateTestResult(result);
}
}
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;
}
}
}
}
}

25
src/AddIns/Analysis/UnitTesting/Commands/IRunTestCommandContext.cs

@ -1,25 +0,0 @@ @@ -1,25 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
public interface IRunTestCommandContext
{
IRegisteredTestFrameworks RegisteredTestFrameworks { get; }
IUnitTestTaskService TaskService { get; }
IUnitTestWorkbench Workbench { get; }
IBuildProjectFactory BuildProjectFactory { get; }
IBuildOptions BuildOptions { get; }
MessageViewCategory UnitTestCategory { get; }
IUnitTestsPad OpenUnitTestsPad { get; }
IMessageService MessageService { get; }
IUnitTestSaveAllFilesCommand SaveAllFilesCommand { get; }
IStatusBarService StatusBarService { get; }
Solution OpenSolution { get; }
}
}

56
src/AddIns/Analysis/UnitTesting/Commands/PadCommands.cs

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.TreeView;
namespace ICSharpCode.UnitTesting
{
public class AddNUnitReferenceCommand : AbstractMenuCommand
{
public void Run(IProject project)
{
if (project != null) {
ReferenceProjectItem nunitRef = new ReferenceProjectItem(project, "nunit.framework");
ProjectService.AddProjectItem(project, nunitRef);
project.Save();
}
}
public override void Run()
{
Run(ProjectService.CurrentProject);
}
}
public class GotoDefinitionCommand : AbstractMenuCommand
{
public override void Run()
{
ITestTreeView treeView = Owner as ITestTreeView;
if (treeView != null) {
ITest test = treeView.SelectedTests.FirstOrDefault();
if (test != null && test.SupportsGoToDefinition)
test.GoToDefinition();
}
}
}
public class CollapseAllTestsCommand : AbstractMenuCommand
{
public override void Run()
{
if (!(this.Owner is SharpTreeView))
return;
var treeView = (SharpTreeView)this.Owner;
if (treeView.Root != null) {
foreach (var n in treeView.Root.Descendants())
n.IsExpanded = false;
}
}
}
}

26
src/AddIns/Analysis/UnitTesting/Commands/RunAllTestsInPadCommand.cs

@ -1,26 +0,0 @@ @@ -1,26 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
namespace ICSharpCode.UnitTesting
{
public class RunAllTestsInPadCommand : RunTestInPadCommand
{
public RunAllTestsInPadCommand()
{
}
public RunAllTestsInPadCommand(IRunTestCommandContext context)
: base(context)
{
}
public override void Run()
{
// To make sure all tests are run we set the Owner to null.
Owner = null;
base.Run();
}
}
}

42
src/AddIns/Analysis/UnitTesting/Commands/RunProjectTestsInPadCommand.cs

@ -1,42 +0,0 @@ @@ -1,42 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
public class RunProjectTestsInPadCommand : RunTestInPadCommand, ITestTreeView
{
public RunProjectTestsInPadCommand()
{
}
public RunProjectTestsInPadCommand(IRunTestCommandContext context)
: base(context)
{
}
public override void Run()
{
Owner = this;
base.Run();
}
public TestMember SelectedMember {
get { return null; }
}
public TestClass SelectedClass {
get { return null; }
}
public TestProject SelectedProject {
get { return TestService.Solution.GetTestProject(ProjectService.CurrentProject); }
}
public string SelectedNamespace {
get { return null; }
}
}
}

68
src/AddIns/Analysis/UnitTesting/Commands/RunTestCommandContext.cs

@ -1,68 +0,0 @@ @@ -1,68 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
public class RunTestCommandContext : IRunTestCommandContext
{
UnitTestingOptions options = UnitTestingOptions.Instance.Clone();
IRegisteredTestFrameworks testFrameworks = TestService.RegisteredTestFrameworks;
UnitTestTaskService taskService = new UnitTestTaskService();
UnitTestWorkbench workbench = new UnitTestWorkbench();
UnitTestBuildProjectFactory buildProjectFactory = new UnitTestBuildProjectFactory();
UnitTestBuildOptions buildOptions = new UnitTestBuildOptions();
MessageViewCategory unitTestCategory = TestService.UnitTestMessageView;
UnitTestSaveAllFilesCommand saveAllFilesCommand = new UnitTestSaveAllFilesCommand();
IStatusBarService statusBarService = SD.StatusBar;
public IRegisteredTestFrameworks RegisteredTestFrameworks {
get { return testFrameworks; }
}
public IUnitTestTaskService TaskService {
get { return taskService; }
}
public IUnitTestWorkbench Workbench {
get { return workbench; }
}
public IBuildProjectFactory BuildProjectFactory {
get { return buildProjectFactory; }
}
public IBuildOptions BuildOptions {
get { return buildOptions; }
}
public MessageViewCategory UnitTestCategory {
get { return unitTestCategory; }
}
public IUnitTestsPad OpenUnitTestsPad {
get { return null; }
}
public IMessageService MessageService {
get { return SD.MessageService; }
}
public IUnitTestSaveAllFilesCommand SaveAllFilesCommand {
get { return saveAllFilesCommand; }
}
public IStatusBarService StatusBarService {
get { return statusBarService; }
}
public Solution OpenSolution {
get { return ProjectService.OpenSolution; }
}
}
}

26
src/AddIns/Analysis/UnitTesting/Commands/RunTestInPadCommand.cs

@ -1,26 +0,0 @@ @@ -1,26 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Util;
namespace ICSharpCode.UnitTesting
{
public class RunTestInPadCommand : AbstractRunTestCommand
{
public RunTestInPadCommand()
{
}
public RunTestInPadCommand(IRunTestCommandContext context)
: base(context)
{
}
protected override ITestRunner CreateTestRunner(IProject project)
{
return Context.RegisteredTestFrameworks.CreateTestRunner(project);
}
}
}

26
src/AddIns/Analysis/UnitTesting/Commands/RunTestWithDebuggerCommand.cs

@ -1,26 +0,0 @@ @@ -1,26 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Diagnostics;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
public class RunTestWithDebuggerCommand : AbstractRunTestCommand
{
public RunTestWithDebuggerCommand()
{
}
public RunTestWithDebuggerCommand(IRunTestCommandContext context)
: base(context)
{
}
protected override ITestRunner CreateTestRunner(IProject project)
{
return Context.RegisteredTestFrameworks.CreateTestDebugger(project);
}
}
}

4
src/AddIns/Analysis/UnitTesting/Commands/RunningTestsCondition.cs

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
using System;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
namespace ICSharpCode.UnitTesting
{
@ -13,7 +14,8 @@ namespace ICSharpCode.UnitTesting @@ -13,7 +14,8 @@ namespace ICSharpCode.UnitTesting
{
public bool IsValid(object caller, Condition condition)
{
return AbstractRunTestCommand.IsRunningTest;
ITestService testService = SD.GetRequiredService<ITestService>();
return testService.IsRunningTests;
}
}
}

88
src/AddIns/Analysis/UnitTesting/Commands/TestableCondition.cs

@ -2,13 +2,13 @@ @@ -2,13 +2,13 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Bookmarks;
using ICSharpCode.SharpDevelop.Editor.Commands;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
@ -17,90 +17,36 @@ namespace ICSharpCode.UnitTesting @@ -17,90 +17,36 @@ namespace ICSharpCode.UnitTesting
/// </summary>
public class TestableCondition : IConditionEvaluator
{
IRegisteredTestFrameworks testFrameworks;
public TestableCondition(IRegisteredTestFrameworks testFrameworks)
{
this.testFrameworks = testFrameworks;
}
readonly ITestService testService;
public TestableCondition()
: this(TestService.RegisteredTestFrameworks)
{
}
public static IMember GetMember(object caller)
{
ITestTreeView testTreeView = caller as ITestTreeView;
if (testTreeView != null && testTreeView.SelectedMember != null) {
return testTreeView.SelectedMember.Resolve(testTreeView.SelectedProject);
}
IEntity entity = ResolveResultMenuCommand.GetEntity(caller);
return entity as IMember;
}
public static ITypeDefinition GetClass(object caller)
{
ITestTreeView testTreeView = caller as ITestTreeView;
if (testTreeView != null && testTreeView.SelectedClass != null) {
return testTreeView.SelectedClass.Resolve(testTreeView.SelectedProject);
}
IEntity entity = ResolveResultMenuCommand.GetEntity(caller);
return entity as ITypeDefinition;
}
public static IProject GetProject(object caller)
{
ITestTreeView testTreeView = caller as ITestTreeView;
if (testTreeView != null) {
return testTreeView.SelectedProject != null ? testTreeView.SelectedProject.Project : null;
}
ITypeDefinition c = GetClassFromMemberOrCaller(caller);
return GetProject(c);
this.testService = SD.GetRequiredService<ITestService>();
}
public static ITypeDefinition GetClassFromMemberOrCaller(object caller)
public TestableCondition(ITestService testService)
{
IMember m = GetMember(caller);
if (m != null) {
return m.DeclaringTypeDefinition;
}
return GetClass(caller);
this.testService = testService;
}
static IProject GetProject(ITypeDefinition c)
public bool IsValid(object caller, Condition condition)
{
return c != null ? c.ParentAssembly.GetProject() : null;
return GetTests(testService.OpenSolution, caller).Any();
}
/// <summary>
/// Returns the namespace selected if any.
/// </summary>
public static string GetNamespace(object caller)
public static IEnumerable<ITest> GetTests(ITestSolution testSolution, object caller)
{
ITestTreeView testTreeView = caller as ITestTreeView;
if (testTreeView != null) {
return testTreeView.SelectedNamespace;
return testTreeView.SelectedTests;
}
return null;
}
public bool IsValid(object caller, Condition condition)
{
IMember m = GetMember(caller);
if (m != null) {
return testFrameworks.IsTestMember(m);
}
ITypeDefinition c = GetClass(caller);
if (ClassHasProject(c)) {
return testFrameworks.IsTestClass(c);
if (testSolution != null) {
IEntity entity = ResolveResultMenuCommand.GetEntity(caller);
ITest test = testSolution.GetTestForEntity(entity);
if (test != null)
return new[] { test };
}
return false;
}
static bool ClassHasProject(ITypeDefinition c)
{
return (c != null) && (c.ParentAssembly.GetProject() != null);
return Enumerable.Empty<ITest>();
}
}
}

70
src/AddIns/Analysis/UnitTesting/Commands/UnitTestCommands.cs

@ -2,78 +2,64 @@ @@ -2,78 +2,64 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.TreeView;
namespace ICSharpCode.UnitTesting
{
public class StopTestsCommand : AbstractMenuCommand
public class RunAllTestsInProjectCommand : AbstractMenuCommand
{
public override void Run()
{
AbstractRunTestCommand runTestCommand = AbstractRunTestCommand.RunningTestCommand;
if (runTestCommand != null) {
runTestCommand.Stop();
ITestService testService = SD.GetRequiredService<ITestService>();
if (testService.OpenSolution != null) {
ITestProject project = testService.OpenSolution.GetTestProject(ProjectService.CurrentProject);
if (project != null)
testService.RunTestsAsync(new [] { project }, new TestExecutionOptions()).FireAndForget();
}
}
}
public class AddNUnitReferenceCommand : AbstractMenuCommand
public class RunAllTestsInSolutionCommand : AbstractMenuCommand
{
public void Run(IProject project)
public override void Run()
{
if (project != null) {
ReferenceProjectItem nunitRef = new ReferenceProjectItem(project, "nunit.framework");
ProjectService.AddProjectItem(project, nunitRef);
project.Save();
}
ITestService testService = SD.GetRequiredService<ITestService>();
if (testService.OpenSolution != null)
testService.RunTestsAsync(new [] { testService.OpenSolution }, new TestExecutionOptions()).FireAndForget();
}
}
public class RunSelectedTestCommand : AbstractMenuCommand
{
public override void Run()
{
Run(ProjectService.CurrentProject);
ITestService testService = SD.GetRequiredService<ITestService>();
IEnumerable<ITest> tests = TestableCondition.GetTests(testService.OpenSolution, Owner);
testService.RunTestsAsync(tests, new TestExecutionOptions()).FireAndForget();
}
}
public class GotoDefinitionCommand : AbstractMenuCommand
public class RunSelectedTestWithDebuggerCommand : AbstractMenuCommand
{
public override void Run()
{
ITestTreeView treeView = Owner as ITestTreeView;
if (treeView != null) {
var member = treeView.SelectedMember;
var c = treeView.SelectedClass;
IEntity entity;
if (member != null) {
entity = member.Resolve(treeView.SelectedProject);
} else if (c != null) {
entity = c.Resolve(treeView.SelectedProject);
} else {
entity = null;
}
if (entity != null) {
NavigationService.NavigateTo(entity);
}
}
ITestService testService = SD.GetRequiredService<ITestService>();
IEnumerable<ITest> tests = TestableCondition.GetTests(testService.OpenSolution, Owner);
testService.RunTestsAsync(tests, new TestExecutionOptions { UseDebugger = true }).FireAndForget();
}
}
public class CollapseAllTestsCommand : AbstractMenuCommand
public class StopTestsCommand : AbstractMenuCommand
{
public override void Run()
{
if (!(this.Owner is SharpTreeView))
return;
var treeView = (SharpTreeView)this.Owner;
if (treeView.Root != null) {
foreach (var n in treeView.Root.Descendants())
n.IsExpanded = false;
}
ITestService testService = SD.GetRequiredService<ITestService>();
testService.CancelRunningTests();
}
}
}

23
src/AddIns/Analysis/UnitTesting/Frameworks/IRegisteredTestFrameworks.cs

@ -1,23 +0,0 @@ @@ -1,23 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
public interface IRegisteredTestFrameworks
{
ITestFramework GetTestFrameworkForProject(IProject project);
ITestRunner CreateTestRunner(IProject project);
ITestRunner CreateTestDebugger(IProject project);
bool IsTestMember(IMember member);
bool IsTestClass(ITypeDefinition typeDefinition);
bool IsTestProject(IProject project);
bool IsBuildNeededBeforeTestRunForProject(IProject project);
}
}

14
src/AddIns/Analysis/UnitTesting/Frameworks/ITestFramework.cs

@ -10,15 +10,25 @@ namespace ICSharpCode.UnitTesting @@ -10,15 +10,25 @@ namespace ICSharpCode.UnitTesting
{
public interface ITestFramework
{
/// <summary>
/// Gets whether this test framework supports the specified project.
/// </summary>
bool IsTestProject(IProject project);
/// <summary>
/// Creates a new test project based on the specified project.
/// </summary>
ITestProject CreateTestProject(ITestSolution parentSolution, IProject project);
/*
bool IsTestMember(IMember member);
bool IsTestClass(ITypeDefinition testClass);
bool IsTestProject(IProject project);
IEnumerable<TestMember> GetTestMembersFor(ITypeDefinition typeDefinition);
ITestRunner CreateTestRunner();
ITestRunner CreateTestDebugger();
bool IsBuildNeededBeforeTestRun { get; }
bool IsBuildNeededBeforeTestRun { get; }*/
}
}

12
src/AddIns/Analysis/UnitTesting/Frameworks/ITestFrameworkFactory.cs

@ -1,12 +0,0 @@ @@ -1,12 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
namespace ICSharpCode.UnitTesting
{
public interface ITestFrameworkFactory
{
ITestFramework Create(string className);
}
}

51
src/AddIns/Analysis/UnitTesting/Frameworks/ITestService.cs

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
[SDService]
public interface ITestService
{
/// <summary>
/// Gets the test framework that supports the specified project.
/// </summary>
ITestFramework GetTestFrameworkForProject(IProject project);
MessageViewCategory UnitTestMessageView { get; }
/// <summary>
/// Gets the current test solution.
/// This property should only be accessed by the main thread.
/// </summary>
ITestSolution OpenSolution { get; }
/// <summary>
/// Occurs when the open test solution has changed.
/// </summary>
event EventHandler OpenSolutionChanged;
/// <summary>
/// Builds the project (if necessary) and runs the specified tests.
/// If tests are already running, the existing run is cancelled.
/// </summary>
Task RunTestsAsync(IEnumerable<ITest> selectedTests, TestExecutionOptions options);
/// <summary>
/// Gets whether tests are currently running.
/// </summary>
bool IsRunningTests { get; }
/// <summary>
/// Aborts the current test run.
/// This method has no effect if no tests are running.
/// </summary>
void CancelRunningTests();
}
}

99
src/AddIns/Analysis/UnitTesting/Frameworks/RegisteredTestFrameworks.cs

@ -1,99 +0,0 @@ @@ -1,99 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
public class RegisteredTestFrameworks : IRegisteredTestFrameworks
{
IReadOnlyList<TestFrameworkDescriptor> testFrameworkDescriptors;
public const string AddInPath = "/SharpDevelop/UnitTesting/TestFrameworks";
public RegisteredTestFrameworks(IAddInTree addInTree)
{
testFrameworkDescriptors = addInTree.BuildItems<TestFrameworkDescriptor>(AddInPath, null);
}
public ITestFramework GetTestFrameworkForProject(IProject project)
{
if (project != null) {
foreach (TestFrameworkDescriptor descriptor in testFrameworkDescriptors) {
if (descriptor.IsSupportedProject(project) && descriptor.TestFramework.IsTestProject(project)) {
return descriptor.TestFramework;
}
}
}
return null;
}
public bool IsTestMember(IMember member)
{
ITestFramework testFramework = GetTestFramework(member);
if (testFramework != null) {
return testFramework.IsTestMember(member);
}
return false;
}
ITestFramework GetTestFramework(IEntity entity)
{
if (entity != null) {
return GetTestFrameworkForProject(entity.ParentAssembly.GetProject());
}
return null;
}
public bool IsTestClass(ITypeDefinition c)
{
ITestFramework testFramework = GetTestFramework(c);
if (testFramework != null) {
return testFramework.IsTestClass(c);
}
return false;
}
public bool IsTestProject(IProject project)
{
ITestFramework testFramework = GetTestFrameworkForProject(project);
if (testFramework != null) {
return testFramework.IsTestProject(project);
}
return false;
}
public ITestRunner CreateTestRunner(IProject project)
{
ITestFramework testFramework = GetTestFrameworkForProject(project);
if (testFramework != null) {
return testFramework.CreateTestRunner();
}
return null;
}
public ITestRunner CreateTestDebugger(IProject project)
{
ITestFramework testFramework = GetTestFrameworkForProject(project);
if (testFramework != null) {
return testFramework.CreateTestDebugger();
}
return null;
}
public bool IsBuildNeededBeforeTestRunForProject(IProject project)
{
ITestFramework testFramework = GetTestFrameworkForProject(project);
if (testFramework != null) {
return testFramework.IsBuildNeededBeforeTestRun;
}
return true;
}
}
}

88
src/AddIns/Analysis/UnitTesting/Frameworks/SDTestService.cs

@ -0,0 +1,88 @@ @@ -0,0 +1,88 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.UnitTesting.Frameworks;
namespace ICSharpCode.UnitTesting
{
sealed class SDTestService : ITestService
{
#region Test Framework Management
const string AddInPath = "/SharpDevelop/UnitTesting/TestFrameworks";
IReadOnlyList<TestFrameworkDescriptor> testFrameworkDescriptors = SD.AddInTree.BuildItems<TestFrameworkDescriptor>(AddInPath, null);
public ITestFramework GetTestFrameworkForProject(IProject project)
{
if (project != null) {
foreach (TestFrameworkDescriptor descriptor in testFrameworkDescriptors) {
if (descriptor.IsSupportedProject(project)) {
return descriptor.TestFramework;
}
}
}
return null;
}
#endregion
#region UnitTestMessageView
MessageViewCategory unitTestMessageView;
public MessageViewCategory UnitTestMessageView {
get {
if (unitTestMessageView == null) {
MessageViewCategory.Create(ref unitTestMessageView,
"UnitTesting",
"${res:ICSharpCode.NUnitPad.NUnitPadContent.PadName}");
}
return unitTestMessageView;
}
}
#endregion
#region OpenSolution
TestSolution solution;
public ITestSolution OpenSolution {
get {
SD.MainThread.VerifyAccess();
if (solution == null)
solution = new TestSolution(this, SD.ResourceService);
return solution;
}
}
public event EventHandler OpenSolutionChanged { add {} remove {} }
#endregion
#region RunTests
CancellationTokenSource runTestsCancellationTokenSource;
public bool IsRunningTests {
get { return runTestsCancellationTokenSource != null; }
}
public Task RunTestsAsync(IEnumerable<ITest> selectedTests, TestExecutionOptions options)
{
CancelRunningTests();
runTestsCancellationTokenSource = new CancellationTokenSource();
var executionManager = new TestExecutionManager();
return executionManager.RunTestsAsync(selectedTests, options, runTestsCancellationTokenSource.Token);
}
public void CancelRunningTests()
{
if (runTestsCancellationTokenSource != null) {
runTestsCancellationTokenSource.Cancel();
runTestsCancellationTokenSource = null;
}
}
#endregion
}
}

149
src/AddIns/Analysis/UnitTesting/Frameworks/TestExecutionManager.cs

@ -0,0 +1,149 @@ @@ -0,0 +1,149 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting.Frameworks
{
/// <summary>
/// Manages the execution of tests across multiple projects.
/// Takes care of building the projects (if necessary) and showing progress in the UI.
/// </summary>
public class TestExecutionManager
{
readonly IBuildProjectFactory buildProjectFactory;
readonly IUnitTestTaskService taskService;
readonly IUnitTestSaveAllFilesCommand saveAllFilesCommand;
readonly ITestService testService;
readonly IWorkbench workbench;
readonly IStatusBarService statusBarService;
readonly IBuildOptions buildOptions;
public TestExecutionManager()
{
this.buildProjectFactory = new UnitTestBuildProjectFactory();
this.taskService = new UnitTestTaskService();
this.saveAllFilesCommand = new UnitTestSaveAllFilesCommand();
this.testService = SD.GetRequiredService<ITestService>();
this.workbench = SD.Workbench;
this.statusBarService = SD.StatusBar;
this.buildOptions = new UnitTestBuildOptions();
}
readonly MultiDictionary<ITestProject, ITest> testsByProject = new MultiDictionary<ITestProject, ITest>();
CancellationToken cancellationToken;
public async Task RunTestsAsync(IEnumerable<ITest> selectedTests, TestExecutionOptions options, CancellationToken cancellationToken)
{
this.cancellationToken = cancellationToken;
GroupTestsByProject(selectedTests);
ClearTasks();
ShowUnitTestsPad();
ShowOutputPad();
ResetTestResults();
saveAllFilesCommand.SaveAllFiles();
// Run the build, if necessary:
var projectsToBuild = testsByProject.Keys.Select(p => p.GetBuildableForTesting()).Where(b => b != null).ToList();
if (projectsToBuild.Count > 0) {
var buildCommand = buildProjectFactory.CreateBuildProjectBeforeTestRun(projectsToBuild);
var buildResults = await buildCommand.BuildAsync(cancellationToken);
if (buildResults.Result != BuildResultCode.Success)
return;
}
cancellationToken.ThrowIfCancellationRequested();
using (IProgressMonitor progressMonitor = statusBarService.CreateProgressMonitor(cancellationToken)) {
int projectsLeftToRun = testsByProject.Count;
foreach (IGrouping<ITestProject, ITest> g in testsByProject) {
ITestProject project = g.Key;
progressMonitor.TaskName = GetProgressMonitorLabel(project);
progressMonitor.Progress = GetProgress(projectsLeftToRun);
using (IProgressMonitor nested = progressMonitor.CreateSubTask(1.0 / testsByProject.Count)) {
await project.RunTestsAsync(g, options, nested);
}
projectsLeftToRun--;
progressMonitor.CancellationToken.ThrowIfCancellationRequested();
}
}
ShowErrorList();
}
void GroupTestsByProject(IEnumerable<ITest> selectedTests)
{
foreach (ITest test in selectedTests) {
if (test == null)
continue;
if (test.ParentProject == null) {
// When a solution is selected, select all its projects individually
foreach (ITest project in test.NestedTests) {
Debug.Assert(project == project.ParentProject);
testsByProject.Add(project.ParentProject, project);
}
} else {
testsByProject.Add(test.ParentProject, test);
}
cancellationToken.ThrowIfCancellationRequested();
}
}
void ClearTasks()
{
taskService.BuildMessageViewCategory.ClearText();
taskService.ClearExceptCommentTasks();
testService.UnitTestMessageView.ClearText();
}
void ShowUnitTestsPad()
{
workbench.GetPad(typeof(UnitTestsPad)).BringPadToFront();
}
void ShowOutputPad()
{
workbench.GetPad(typeof(CompilerMessageView)).BringPadToFront();
}
void ResetTestResults()
{
cancellationToken.ThrowIfCancellationRequested();
foreach (ITest test in testsByProject.Values) {
test.ResetTestResults();
}
cancellationToken.ThrowIfCancellationRequested();
}
string GetProgressMonitorLabel(ITestProject project)
{
StringTagPair tagPair = new StringTagPair("Name", project.DisplayName);
return StringParser.Parse("${res:ICSharpCode.UnitTesting.StatusBarProgressLabel}", tagPair);
}
double GetProgress(int projectsLeftToRunCount)
{
int totalProjectCount = testsByProject.Count;
return (double)(totalProjectCount - projectsLeftToRunCount) / totalProjectCount;
}
void ShowErrorList()
{
if (taskService.SomethingWentWrong && buildOptions.ShowErrorListAfterBuild) {
workbench.GetPad(typeof(ErrorListPad)).BringPadToFront();
}
}
}
}

19
src/AddIns/Analysis/UnitTesting/Frameworks/TestExecutionOptions.cs

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// Options used for test execution.
/// </summary>
public class TestExecutionOptions
{
/// <summary>
/// Gets/Sets whether to debug the test execution.
/// The default is <c>false</c>.
/// </summary>
public bool UseDebugger { get; set; }
}
}

8
src/AddIns/Analysis/UnitTesting/Frameworks/TestFrameworkDescriptor.cs

@ -12,14 +12,14 @@ namespace ICSharpCode.UnitTesting @@ -12,14 +12,14 @@ namespace ICSharpCode.UnitTesting
public class TestFrameworkDescriptor
{
Properties properties;
ITestFrameworkFactory factory;
Func<string, object> objectFactory;
ITestFramework testFramework;
List<string> supportedProjectFileExtensions = new List<string>();
public TestFrameworkDescriptor(Properties properties, ITestFrameworkFactory factory)
public TestFrameworkDescriptor(Properties properties, Func<string, object> objectFactory)
{
this.properties = properties;
this.factory = factory;
this.objectFactory = objectFactory;
GetSupportedProjectFileExtensions();
}
@ -47,7 +47,7 @@ namespace ICSharpCode.UnitTesting @@ -47,7 +47,7 @@ namespace ICSharpCode.UnitTesting
void CreateTestFrameworkIfNotCreated()
{
if (testFramework == null) {
testFramework = factory.Create(ClassName);
testFramework = (ITestFramework)objectFactory(ClassName);
}
}

7
src/AddIns/Analysis/UnitTesting/Frameworks/TestFrameworkDoozer.cs

@ -19,12 +19,7 @@ namespace ICSharpCode.UnitTesting @@ -19,12 +19,7 @@ namespace ICSharpCode.UnitTesting
public object BuildItem(BuildItemArgs args)
{
return BuildItem(args.Codon, new TestFrameworkFactory(args.AddIn));
}
public TestFrameworkDescriptor BuildItem(Codon codon, ITestFrameworkFactory factory)
{
return new TestFrameworkDescriptor(codon.Properties, factory);
return new TestFrameworkDescriptor(args.Codon.Properties, args.AddIn.CreateObject);
}
}
}

23
src/AddIns/Analysis/UnitTesting/Frameworks/TestFrameworkFactory.cs

@ -1,23 +0,0 @@ @@ -1,23 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.Core;
namespace ICSharpCode.UnitTesting
{
public class TestFrameworkFactory : ITestFrameworkFactory
{
AddIn addin;
public TestFrameworkFactory(AddIn addin)
{
this.addin = addin;
}
public ITestFramework Create(string className)
{
return addin.CreateObject(className) as ITestFramework;
}
}
}

57
src/AddIns/Analysis/UnitTesting/Frameworks/TestService.cs

@ -1,57 +0,0 @@ @@ -1,57 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui;
namespace ICSharpCode.UnitTesting
{
public static class TestService
{
static IRegisteredTestFrameworks testFrameworks;
static MessageViewCategory unitTestMessageView;
public static IRegisteredTestFrameworks RegisteredTestFrameworks {
get {
CreateRegisteredTestFrameworks();
return testFrameworks;
}
set { testFrameworks = value; }
}
static void CreateRegisteredTestFrameworks()
{
if (testFrameworks == null) {
testFrameworks = new RegisteredTestFrameworks(SD.AddInTree);
}
}
public static MessageViewCategory UnitTestMessageView {
get {
if (unitTestMessageView == null) {
CreateUnitTestCategory();
}
return unitTestMessageView;
}
}
static void CreateUnitTestCategory()
{
MessageViewCategory.Create(ref unitTestMessageView,
"UnitTesting",
"${res:ICSharpCode.NUnitPad.NUnitPadContent.PadName}");
}
static TestSolution solution;
public static TestSolution Solution {
get {
SD.MainThread.VerifyAccess();
if (solution == null)
solution = new TestSolution(RegisteredTestFrameworks);
return solution;
}
}
}
}

2
src/AddIns/Analysis/UnitTesting/Interfaces/IBuildProjectFactory.cs

@ -10,6 +10,6 @@ namespace ICSharpCode.UnitTesting @@ -10,6 +10,6 @@ namespace ICSharpCode.UnitTesting
{
public interface IBuildProjectFactory
{
BuildProject CreateBuildProjectBeforeTestRun(IEnumerable<IProject> projects);
BuildProject CreateBuildProjectBeforeTestRun(IEnumerable<IBuildable> projects);
}
}

1
src/AddIns/Analysis/UnitTesting/Interfaces/IUnitTestTaskService.cs

@ -11,7 +11,6 @@ namespace ICSharpCode.UnitTesting @@ -11,7 +11,6 @@ namespace ICSharpCode.UnitTesting
public interface IUnitTestTaskService
{
MessageViewCategory BuildMessageViewCategory { get; }
bool InUpdate { get; set; }
void ClearExceptCommentTasks();
void Add(SDTask task);
bool SomethingWentWrong { get; }

15
src/AddIns/Analysis/UnitTesting/Interfaces/IUnitTestWorkbench.cs

@ -1,15 +0,0 @@ @@ -1,15 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.SharpDevelop;
namespace ICSharpCode.UnitTesting
{
public interface IUnitTestWorkbench
{
PadDescriptor GetPad(Type type);
void SafeThreadAsyncCall(Action method);
void SafeThreadAsyncCall<A>(Action<A> method, A arg1);
}
}

2
src/AddIns/Analysis/UnitTesting/Interfaces/UnitTestBuildProjectFactory.cs

@ -10,7 +10,7 @@ namespace ICSharpCode.UnitTesting @@ -10,7 +10,7 @@ namespace ICSharpCode.UnitTesting
{
public class UnitTestBuildProjectFactory : IBuildProjectFactory
{
public BuildProject CreateBuildProjectBeforeTestRun(IEnumerable<IProject> projects)
public BuildProject CreateBuildProjectBeforeTestRun(IEnumerable<IBuildable> projects)
{
return new BuildProjectBeforeExecute(new MultipleProjectBuildable(projects));
}

5
src/AddIns/Analysis/UnitTesting/Interfaces/UnitTestTaskService.cs

@ -14,11 +14,6 @@ namespace ICSharpCode.UnitTesting @@ -14,11 +14,6 @@ namespace ICSharpCode.UnitTesting
TaskService.ClearExceptCommentTasks();
}
public bool InUpdate {
get { return TaskService.InUpdate; }
set { TaskService.InUpdate = value; }
}
public MessageViewCategory BuildMessageViewCategory {
get { return TaskService.BuildMessageViewCategory; }
}

27
src/AddIns/Analysis/UnitTesting/Interfaces/UnitTestWorkbench.cs

@ -1,27 +0,0 @@ @@ -1,27 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui;
namespace ICSharpCode.UnitTesting
{
public class UnitTestWorkbench : IUnitTestWorkbench
{
public PadDescriptor GetPad(Type type)
{
return WorkbenchSingleton.Workbench.GetPad(type);
}
public void SafeThreadAsyncCall(Action method)
{
WorkbenchSingleton.SafeThreadAsyncCall(method);
}
public void SafeThreadAsyncCall<A>(Action<A> method, A arg1)
{
WorkbenchSingleton.SafeThreadAsyncCall(method, arg1);
}
}
}

55
src/AddIns/Analysis/UnitTesting/Model/ITest.cs

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.ObjectModel;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// Represents a unit test or a group of unit tests.
/// </summary>
public interface ITest
{
/// <summary>
/// Gets the collection of nested tests.
/// </summary>
TestCollection NestedTests { get; }
/// <summary>
/// Gets the parent project that owns this test.
/// </summary>
ITestProject ParentProject { get; }
/// <summary>
/// Name to be displayed in the tests tree view.
/// </summary>
string DisplayName { get; }
/// <summary>
/// Raised when the <see cref="Name"/> property changes.
/// </summary>
event EventHandler DisplayNameChanged;
/// <summary>
/// Gets the result of the previous run of this test.
/// </summary>
TestResultType Result { get; }
/// <summary>
/// Raised when the <see cref="Result"/> property changes.
/// </summary>
event EventHandler<TestResultTypeChangedEventArgs> ResultChanged;
/// <summary>
/// Resets the test results for this test and all nested tests.
/// </summary>
void ResetTestResults();
bool SupportsGoToDefinition { get; }
void GoToDefinition();
UnitTestNode CreateTreeNode();
}
}

47
src/AddIns/Analysis/UnitTesting/Model/ITestProject.cs

@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// Represents the root node of a test project.
/// </summary>
public interface ITestProject : ITest
{
/// <summary>
/// Gets the SharpDevelop project on which this test project is based.
/// </summary>
IProject Project { get; }
/// <summary>
/// Gets the test for the specified entity.
/// Returns null if the entity is not a unit test.
/// </summary>
ITest GetTestForEntity(IEntity entity);
/// <summary>
/// Returns a SharpDevelop <see cref="IBuildable"/> that builds the project
/// for test execution.
/// May return null if the project does not require compilation.
/// </summary>
IBuildable GetBuildableForTesting();
/// <summary>
/// Notifies the project that the parse information was changed.
/// </summary>
void NotifyParseInformationChanged(IUnresolvedFile oldUnresolvedFile, IUnresolvedFile newUnresolvedFile);
/// <summary>
/// Runs the specified tests. The specified tests must belong to this project.
/// </summary>
Task RunTestsAsync(IEnumerable<ITest> tests, TestExecutionOptions options, IProgressMonitor progressMonitor);
}
}

33
src/AddIns/Analysis/UnitTesting/Model/ITestSolution.cs

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.ObjectModel;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// A test that represents the whole solution.
/// </summary>
public interface ITestSolution : ITest
{
// /// <summary>
// /// Gets the list of all test projects.
// /// </summary>
// ObservableCollection<ITestProject> TestableProjects { get; }
/// <summary>
/// Gets the test project for the specified project.
/// Returns null if the project is not a test project.
/// </summary>
ITestProject GetTestProject(IProject project);
/// <summary>
/// Gets the test for the specified entity.
/// Returns null if the entity is not a unit test.
/// </summary>
ITest GetTestForEntity(IEntity entity);
}
}

143
src/AddIns/Analysis/UnitTesting/Model/TestBase.cs

@ -0,0 +1,143 @@ @@ -0,0 +1,143 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// Base class for <see cref="ITest"/> implementations.
/// </summary>
public abstract class TestBase : ITest
{
public abstract string DisplayName { get; }
public virtual event EventHandler DisplayNameChanged { add {} remove {} }
public abstract ITestProject ParentProject { get; }
#region Result
TestResultType result;
bool useCompositeResultsOfNestedTests;
public event EventHandler<TestResultTypeChangedEventArgs> ResultChanged;
/// <summary>
/// Gets/Sets the test result.
/// </summary>
/// <remarks>
/// If the result is bound to the composite of the nested tests, setting this
/// property will remove the binding.
/// </remarks>
public TestResultType Result {
get { return result; }
protected set {
if (useCompositeResultsOfNestedTests) {
nestedTests.PropertyChanged -= nestedTestsCollection_PropertyChanged;
useCompositeResultsOfNestedTests = false;
}
ChangeResult(value);
}
}
void ChangeResult(TestResultType newResult)
{
TestResultType oldResult = result;
if (oldResult != newResult) {
result = newResult;
OnResultChanged(new TestResultTypeChangedEventArgs(oldResult, newResult));
}
}
/// <summary>
/// Binds the result to the composite result of the nested tests.
/// </summary>
protected void BindResultToCompositeResultOfNestedTests()
{
if (!useCompositeResultsOfNestedTests) {
useCompositeResultsOfNestedTests = true;
if (nestedTests != null) {
nestedTests.PropertyChanged += nestedTestsCollection_PropertyChanged;
ChangeResult(nestedTests.CompositeResult);
} else {
ChangeResult(TestResultType.None);
}
}
}
void nestedTestsCollection_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == null || e.PropertyName == "CompositeResult") {
ChangeResult(nestedTests.CompositeResult);
}
}
protected virtual void OnResultChanged(TestResultTypeChangedEventArgs e)
{
if (ResultChanged != null) {
ResultChanged(this, e);
}
}
#endregion
#region NestedTests
TestCollection nestedTests;
public TestCollection NestedTests {
get {
if (nestedTests == null) {
nestedTests = InitializeNestedTests();
OnNestedTestsInitialized();
}
return nestedTests;
}
}
protected bool NestedTestsInitialized {
get { return nestedTests != null; }
}
protected virtual TestCollection InitializeNestedTests()
{
return new TestCollection();
}
protected virtual void OnNestedTestsInitialized()
{
// If we're supposed to be bound to the composite result of the nested tests,
// but the nested test collection wasn't initialized yet,
// we will recreate the binding.
if (useCompositeResultsOfNestedTests) {
useCompositeResultsOfNestedTests = false;
BindResultToCompositeResultOfNestedTests();
}
}
#endregion
public virtual void ResetTestResults()
{
if (nestedTests != null) {
foreach (ITest test in nestedTests) {
test.ResetTestResults();
}
}
if (!useCompositeResultsOfNestedTests)
this.Result = TestResultType.None;
}
public virtual bool SupportsGoToDefinition {
get { return false; }
}
public void GoToDefinition()
{
throw new NotSupportedException();
}
public virtual UnitTestNode CreateTreeNode()
{
return new UnitTestNode(this);
}
}
}

199
src/AddIns/Analysis/UnitTesting/Model/TestCollection.cs

@ -0,0 +1,199 @@ @@ -0,0 +1,199 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// Collection of tests that monitors the amount of tests for each result type,
/// allowing efficient updates of the overall result.
/// </summary>
public class TestCollection : ObservableCollection<ITest>
{
#region Struct TestCounts
struct TestCounts
{
internal int indeterminate;
internal int successful;
internal int failed;
internal int ignored;
public TestResultType CompositeResult {
get {
if (failed > 0)
return TestResultType.Failure;
if (indeterminate > 0)
return TestResultType.None;
if (ignored > 0)
return TestResultType.Ignored;
if (successful > 0)
return TestResultType.Success;
return TestResultType.None;
}
}
public void Add(TestResultType result)
{
switch (result) {
case TestResultType.None:
indeterminate++;
break;
case TestResultType.Success:
successful++;
break;
case TestResultType.Failure:
failed++;
break;
case TestResultType.Ignored:
ignored++;
break;
default:
throw new NotSupportedException("Invalid value for TestResultType");
}
}
public void Remove(TestResultType result)
{
switch (result) {
case TestResultType.None:
indeterminate--;
break;
case TestResultType.Success:
successful--;
break;
case TestResultType.Failure:
failed--;
break;
case TestResultType.Ignored:
ignored--;
break;
default:
throw new NotSupportedException("Invalid value for TestResultType");
}
}
}
#endregion
public static TestResultType GetCompositeResult(IEnumerable<ITest> tests)
{
TestCounts c = new TestCounts();
foreach (ITest test in tests) {
c.Add(test.Result);
}
return c.CompositeResult;
}
#region Properties
TestCounts counts;
public int IndeterminateNestedTestCount {
get { return counts.indeterminate; }
}
public int SuccessfulNestedTestCount {
get { return counts.successful; }
}
public int FailedNestedTestCount {
get { return counts.failed; }
}
public int IgnoredNestedTestCount {
get { return counts.ignored; }
}
public TestResultType CompositeResult {
get { return counts.CompositeResult; }
}
static readonly PropertyChangedEventArgs indeterminateArgs = new PropertyChangedEventArgs("IndeterminateNestedTestCount");
static readonly PropertyChangedEventArgs successfulArgs = new PropertyChangedEventArgs("SuccessfulNestedTestCount");
static readonly PropertyChangedEventArgs failedArgs = new PropertyChangedEventArgs("FailedNestedTestCount");
static readonly PropertyChangedEventArgs ignoredArgs = new PropertyChangedEventArgs("IgnoredNestedTestCount");
static readonly PropertyChangedEventArgs compositeResultArgs = new PropertyChangedEventArgs("CompositeResult");
void RaiseCountChangeEvents(TestCounts old)
{
if (old.indeterminate != counts.indeterminate)
OnPropertyChanged(indeterminateArgs);
if (old.successful != counts.successful)
OnPropertyChanged(successfulArgs);
if (old.failed != counts.failed)
OnPropertyChanged(failedArgs);
if (old.ignored != counts.ignored)
OnPropertyChanged(ignoredArgs);
if (old.CompositeResult != counts.CompositeResult)
OnPropertyChanged(compositeResultArgs);
}
// change visibility of PropertyChanged event to public
public new event PropertyChangedEventHandler PropertyChanged {
add { base.PropertyChanged += value; }
remove { base.PropertyChanged -= value; }
}
#endregion
void item_ResultChanged(object sender, TestResultTypeChangedEventArgs e)
{
TestCounts old = counts;
counts.Remove(e.OldResult);
counts.Add(e.NewResult);
RaiseCountChangeEvents(old);
}
protected override void ClearItems()
{
TestCounts old = counts;
counts = default(TestCounts);
foreach (ITest test in Items) {
counts.Remove(test.Result);
test.ResultChanged -= item_ResultChanged;
}
base.ClearItems();
RaiseCountChangeEvents(old);
}
protected override void InsertItem(int index, ITest item)
{
if (item == null)
throw new ArgumentNullException("item");
TestCounts old = counts;
counts.Add(item.Result);
base.InsertItem(index, item);
item.ResultChanged += item_ResultChanged;
RaiseCountChangeEvents(old);
}
protected override void RemoveItem(int index)
{
TestCounts old = counts;
ITest oldItem = Items[index];
counts.Remove(oldItem.Result);
oldItem.ResultChanged -= item_ResultChanged;
base.RemoveItem(index);
RaiseCountChangeEvents(old);
}
protected override void SetItem(int index, ITest item)
{
if (item == null)
throw new ArgumentNullException("item");
TestCounts old = counts;
ITest oldItem = Items[index];
counts.Remove(oldItem.Result);
oldItem.ResultChanged -= item_ResultChanged;
counts.Add(item.Result);
item.ResultChanged += item_ResultChanged;
base.SetItem(index, item);
RaiseCountChangeEvents(old);
}
}
}

46
src/AddIns/Analysis/UnitTesting/Model/TestNamespace.cs

@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.ObjectModel;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// Represents a namespace of unit tests.
/// </summary>
public class TestNamespace : TestBase
{
readonly ITestProject project;
readonly string namespaceName;
readonly string displayName;
public TestNamespace(ITestProject project, string namespaceName, string displayName = null)
{
if (project == null)
throw new ArgumentNullException("project");
if (namespaceName == null)
throw new ArgumentNullException("namespaceName");
this.project = project;
this.namespaceName = namespaceName;
if (displayName != null) {
this.displayName = displayName;
} else {
this.displayName = namespaceName.Substring(namespaceName.IndexOf('.') + 1);
}
BindResultToCompositeResultOfNestedTests();
}
public override ITestProject ParentProject {
get { return project; }
}
public string NamespaceName {
get { return namespaceName; }
}
public override string DisplayName {
get { return displayName; }
}
}
}

58
src/AddIns/Analysis/UnitTesting/Model/TestProjectBase.cs

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// Base class for <see cref="ITestProject"/> implementations.
/// </summary>
public abstract class TestProjectBase : TestBase, ITestProject
{
IProject project;
public TestProjectBase(IProject project)
{
if (project == null)
throw new ArgumentNullException("project");
this.project = project;
BindResultToCompositeResultOfNestedTests();
}
public IProject Project {
get { return project; }
}
public override ITestProject ParentProject {
get { return this; }
}
public override string DisplayName {
get { return project.Name; }
}
public virtual ITest GetTestForEntity(IEntity entity)
{
return null;
}
public virtual IBuildable GetBuildableForTesting()
{
return project;
}
public void NotifyParseInformationChanged(IUnresolvedFile oldUnresolvedFile, IUnresolvedFile newUnresolvedFile)
{
if (!NestedTestsInitialized)
return;
}
public abstract Task RunTestsAsync(IEnumerable<ITest> tests, TestExecutionOptions options, IProgressMonitor progressMonitor);
}
}

30
src/AddIns/Analysis/UnitTesting/Model/TestResultTypeChangedEventArgs.cs

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// EventArgs for ITest.ResultChanged.
/// </summary>
public class TestResultTypeChangedEventArgs : EventArgs
{
readonly TestResultType oldResult;
readonly TestResultType newResult;
public TestResultTypeChangedEventArgs(TestResultType oldResult, TestResultType newResult)
{
this.oldResult = oldResult;
this.newResult = newResult;
}
public TestResultType NewResult {
get { return newResult; }
}
public TestResultType OldResult {
get { return oldResult; }
}
}
}

80
src/AddIns/Analysis/UnitTesting/Model/TestSolution.cs

@ -5,7 +5,8 @@ using System; @@ -5,7 +5,8 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Parser;
using ICSharpCode.SharpDevelop.Project;
@ -15,21 +16,20 @@ namespace ICSharpCode.UnitTesting @@ -15,21 +16,20 @@ namespace ICSharpCode.UnitTesting
/// <summary>
/// Manages the collection of TestProjects.
/// </summary>
public class TestSolution
sealed class TestSolution : TestBase, ITestSolution
{
readonly IRegisteredTestFrameworks registeredTestFrameworks;
readonly IResourceService resourceService;
readonly ITestService testService;
readonly List<ProjectChangeListener> changeListeners = new List<ProjectChangeListener>();
readonly ObservableCollection<TestProject> testableProjects = new ObservableCollection<TestProject>();
public ObservableCollection<TestProject> TestableProjects {
get { return testableProjects; }
}
public TestSolution(IRegisteredTestFrameworks registeredTestFrameworks)
public TestSolution(ITestService testService, IResourceService resourceService)
{
if (registeredTestFrameworks == null)
throw new ArgumentNullException("registeredTestFrameworks");
this.registeredTestFrameworks = registeredTestFrameworks;
if (testService == null)
throw new ArgumentNullException("testService");
if (resourceService == null)
throw new ArgumentNullException("resourceService");
this.testService = testService;
this.resourceService = resourceService;
ProjectService.SolutionLoaded += ProjectService_SolutionLoaded;
ProjectService.SolutionClosed += ProjectService_SolutionClosed;
ProjectService.ProjectAdded += ProjectService_ProjectAdded;
@ -40,13 +40,39 @@ namespace ICSharpCode.UnitTesting @@ -40,13 +40,39 @@ namespace ICSharpCode.UnitTesting
SD_ParserService_LoadSolutionProjectsThread_Finished(null, null);
}
}
/// <summary>
/// Retrieves the TestProject for the specified project.
/// </summary>
public TestProject GetTestProject(IProject currentProject)
public override string DisplayName {
get { return resourceService.GetString("ICSharpCode.UnitTesting.AllTestsTreeNode.Text"); }
}
public override event EventHandler DisplayNameChanged {
add { resourceService.LanguageChanged += value; }
remove { resourceService.LanguageChanged -= value; }
}
public override ITestProject ParentProject {
get { return null; }
}
public ITestProject GetTestProject(IProject project)
{
for (int i = 0; i < changeListeners.Count; i++) {
if (changeListeners[i].project == project) {
return changeListeners[i].testProject;
}
}
return null;
}
public ITest GetTestForEntity(IEntity entity)
{
return testableProjects.FirstOrDefault(p => p.Project == currentProject);
if (entity == null)
return null;
ITestProject testProject = GetTestProject(entity.ParentAssembly.GetProject());
if (testProject != null)
return testProject.GetTestForEntity(entity);
else
return null;
}
/// <summary>
@ -57,8 +83,9 @@ namespace ICSharpCode.UnitTesting @@ -57,8 +83,9 @@ namespace ICSharpCode.UnitTesting
class ProjectChangeListener
{
readonly TestSolution testSolution;
ITestFramework oldTestFramework;
internal readonly IProject project;
TestProject testProject;
internal ITestProject testProject;
public ProjectChangeListener(TestSolution testSolution, IProject project)
{
@ -77,7 +104,7 @@ namespace ICSharpCode.UnitTesting @@ -77,7 +104,7 @@ namespace ICSharpCode.UnitTesting
project.ParseInformationUpdated -= project_ParseInformationUpdated;
// Remove old testProject
if (testProject != null) {
testSolution.testableProjects.Remove(testProject);
testSolution.NestedTests.Remove(testProject);
testProject = null;
}
}
@ -91,20 +118,23 @@ namespace ICSharpCode.UnitTesting @@ -91,20 +118,23 @@ namespace ICSharpCode.UnitTesting
internal void CheckTestFramework()
{
ITestFramework newTestFramework = testSolution.registeredTestFrameworks.GetTestFrameworkForProject(project);
if (newTestFramework != null && testProject != null && testProject.TestFramework == newTestFramework)
ITestFramework newTestFramework = testSolution.testService.GetTestFrameworkForProject(project);
if (newTestFramework == oldTestFramework)
return; // test framework is unchanged
// Remove old testProject
if (testProject != null) {
testSolution.testableProjects.Remove(testProject);
testSolution.NestedTests.Remove(testProject);
testProject = null;
}
// Create new testProject
if (newTestFramework != null) {
testProject = new TestProject(project, newTestFramework);
testSolution.testableProjects.Add(testProject);
testProject = newTestFramework.CreateTestProject(testSolution, project);
if (testProject == null)
throw new InvalidOperationException("CreateTestProject() returned null");
testSolution.NestedTests.Add(testProject);
}
oldTestFramework = newTestFramework;
}
}

16
src/AddIns/Analysis/UnitTesting/NUnit/NUnitConsoleApplication.cs

@ -16,18 +16,19 @@ namespace ICSharpCode.UnitTesting @@ -16,18 +16,19 @@ namespace ICSharpCode.UnitTesting
{
public class NUnitConsoleApplication
{
public NUnitConsoleApplication(SelectedTests selectedTests, UnitTestingOptions options)
/*
public NUnitConsoleApplication(ITestProject project, IEnumerable<ITest> selectedTests, UnitTestingOptions options)
{
Initialize(selectedTests);
Initialize(project, selectedTests);
InitializeOptions(options);
}
public NUnitConsoleApplication(SelectedTests selectedTests)
public NUnitConsoleApplication(ITestProject project, IEnumerable<ITest> selectedTests)
{
Initialize(selectedTests);
Initialize(project, selectedTests);
}
void Initialize(SelectedTests selectedTests)
void Initialize(ITestProject project, IEnumerable<ITest> selectedTests)
{
this.selectedTests = selectedTests;
this.project = selectedTests.Project;
@ -42,6 +43,7 @@ namespace ICSharpCode.UnitTesting @@ -42,6 +43,7 @@ namespace ICSharpCode.UnitTesting
}
}
}
*/
void InitializeOptions(UnitTestingOptions options)
{
@ -150,9 +152,9 @@ namespace ICSharpCode.UnitTesting @@ -150,9 +152,9 @@ namespace ICSharpCode.UnitTesting
public string NamespaceFilter;
IProject project;
SelectedTests selectedTests;
IEnumerable<ITest> selectedTests;
public SelectedTests SelectedTests {
public IEnumerable<ITest> SelectedTests {
get { return selectedTests; }
}

4
src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestDebugger.cs

@ -2,7 +2,9 @@ @@ -2,7 +2,9 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Debugging;
@ -30,7 +32,7 @@ namespace ICSharpCode.UnitTesting @@ -30,7 +32,7 @@ namespace ICSharpCode.UnitTesting
this.options = options;
}
protected override ProcessStartInfo GetProcessStartInfo(SelectedTests selectedTests)
protected override ProcessStartInfo GetProcessStartInfo(IEnumerable<ITest> selectedTests)
{
NUnitConsoleApplication app = new NUnitConsoleApplication(selectedTests, options);
app.Results = base.TestResultsMonitor.FileName;

39
src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestFramework.cs

@ -14,23 +14,9 @@ namespace ICSharpCode.UnitTesting @@ -14,23 +14,9 @@ namespace ICSharpCode.UnitTesting
{
public class NUnitTestFramework : ITestFramework
{
public bool IsBuildNeededBeforeTestRun {
get { return true; }
}
public ITestRunner CreateTestRunner()
{
return new NUnitTestRunner();
}
public ITestRunner CreateTestDebugger()
{
return new NUnitTestDebugger();
}
static readonly ITypeReference testAttributeRef = new GetClassTypeReference("NUnit.Framework", "TestAttribute", 0);
static readonly ITypeReference testCaseAttributeRef = new GetClassTypeReference("NUnit.Framework", "TestCaseAttribute", 0);
static readonly ITypeReference testFixtureAttributeRef = new GetClassTypeReference("NUnit.Framework", "TestFixtureAttribute", 0);
readonly ITypeReference testAttributeRef = new GetClassTypeReference("NUnit.Framework", "TestAttribute", 0);
readonly ITypeReference testCaseAttributeRef = new GetClassTypeReference("NUnit.Framework", "TestCaseAttribute", 0);
readonly ITypeReference testFixtureAttributeRef = new GetClassTypeReference("NUnit.Framework", "TestFixtureAttribute", 0);
/// <summary>
/// Determines whether the project is a test project. A project
@ -44,6 +30,23 @@ namespace ICSharpCode.UnitTesting @@ -44,6 +30,23 @@ namespace ICSharpCode.UnitTesting
return testAttributeRef.Resolve(SD.ParserService.GetCompilation(project).TypeResolveContext).Kind != TypeKind.Unknown;
}
public ITestProject CreateTestProject(ITestSolution parentSolution, IProject project)
{
return new NUnitTestProject(project);
}
/*
public ITestRunner CreateTestRunner()
{
return new NUnitTestRunner();
}
public ITestRunner CreateTestDebugger()
{
return new NUnitTestDebugger();
}
public bool IsTestMember(IMember member)
{
if (member == null || member.EntityType != EntityType.Method)
@ -72,6 +75,6 @@ namespace ICSharpCode.UnitTesting @@ -72,6 +75,6 @@ namespace ICSharpCode.UnitTesting
{
var project = typeDefinition.ParentAssembly.GetProject();
return typeDefinition.Methods.Where(IsTestMember).Select(m => new TestMember(m.UnresolvedMember));
}
}*/
}
}

26
src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestProject.cs

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// NUnit test project.
/// </summary>
public class NUnitTestProject : TestProjectBase
{
public NUnitTestProject(IProject project) : base(project)
{
}
public override Task RunTestsAsync(IEnumerable<ITest> tests, TestExecutionOptions options, IProgressMonitor progressMonitor)
{
throw new NotImplementedException();
}
}
}

4
src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestRunner.cs

@ -2,7 +2,9 @@ @@ -2,7 +2,9 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using ICSharpCode.SharpDevelop.Util;
namespace ICSharpCode.UnitTesting
@ -23,7 +25,7 @@ namespace ICSharpCode.UnitTesting @@ -23,7 +25,7 @@ namespace ICSharpCode.UnitTesting
this.options = options;
}
protected override ProcessStartInfo GetProcessStartInfo(SelectedTests selectedTests)
protected override ProcessStartInfo GetProcessStartInfo(IEnumerable<ITest> selectedTests)
{
NUnitConsoleApplication app = new NUnitConsoleApplication(selectedTests, options);
app.Results = base.TestResultsMonitor.FileName;

53
src/AddIns/Analysis/UnitTesting/Pad/EmptyUnitTestsPad.cs

@ -1,53 +0,0 @@ @@ -1,53 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Linq;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
public class EmptyUnitTestsPad : IUnitTestsPad
{
Solution solution;
public EmptyUnitTestsPad()
: this(null)
{
}
public EmptyUnitTestsPad(Solution solution)
{
this.solution = solution;
}
public void UpdateToolbar()
{
}
public void BringToFront()
{
}
public void ResetTestResults()
{
}
public IProject[] GetProjects()
{
if (solution != null) {
return solution.Projects.ToArray();
}
return new IProject[0];
}
public TestProject GetTestProject(IProject project)
{
return null;
}
public void CollapseAll()
{
}
}
}

18
src/AddIns/Analysis/UnitTesting/Pad/IUnitTestsPad.cs

@ -1,18 +0,0 @@ @@ -1,18 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
public interface IUnitTestsPad
{
void UpdateToolbar();
void BringToFront();
void ResetTestResults();
IProject[] GetProjects();
TestProject GetTestProject(IProject project);
void CollapseAll();
}
}

236
src/AddIns/Analysis/UnitTesting/Pad/UnitTestsPad.cs

@ -19,23 +19,20 @@ namespace ICSharpCode.UnitTesting @@ -19,23 +19,20 @@ namespace ICSharpCode.UnitTesting
{
public class UnitTestsPad : AbstractPadContent
{
TestSolution testSolution;
ITestService testService;
TestTreeView treeView;
bool disposed;
DockPanel panel;
ToolBar toolBar;
List<Tuple<IUnresolvedFile, IUnresolvedFile>> pending = new List<Tuple<IUnresolvedFile, IUnresolvedFile>>();
static UnitTestsPad instance;
public UnitTestsPad()
: this(TestService.RegisteredTestFrameworks, TestService.Solution)
: this(SD.GetRequiredService<ITestService>())
{
}
public UnitTestsPad(IRegisteredTestFrameworks testFrameworks, TestSolution testSolution)
public UnitTestsPad(ITestService testService)
{
instance = this;
this.testSolution = testSolution;
this.testService = testService;
panel = new DockPanel();
@ -43,131 +40,28 @@ namespace ICSharpCode.UnitTesting @@ -43,131 +40,28 @@ namespace ICSharpCode.UnitTesting
panel.Children.Add(toolBar);
DockPanel.SetDock(toolBar, Dock.Top);
treeView = new TestTreeView(testFrameworks, testSolution);
treeView = new TestTreeView();
panel.Children.Add(treeView);
// Add the load solution projects thread ended handler before
// we try to display the open solution so the event does not
// get missed.
SD.ParserService.LoadSolutionProjectsThread.Finished += LoadSolutionProjectsThreadFinished;
OnAddedLoadSolutionProjectsThreadEndedHandler();
ProjectService.SolutionClosed += SolutionClosed;
ProjectService.SolutionFolderRemoved += SolutionFolderRemoved;
ProjectService.ProjectAdded += ProjectAdded;
ProjectService.ProjectItemAdded += ProjectItemAdded;
ProjectService.ProjectItemRemoved += ProjectItemRemoved;
treeView.ContextMenu = CreateContextMenu("/SharpDevelop/Pads/UnitTestsPad/ContextMenu");
}
public static UnitTestsPad Instance {
get { return instance; }
}
public override object Control {
get { return panel; }
testService.OpenSolutionChanged += testService_OpenSolutionChanged;
testService_OpenSolutionChanged(null, null);
}
public override void Dispose()
{
if (!disposed) {
disposed = true;
ProjectService.ProjectItemRemoved -= ProjectItemRemoved;
ProjectService.ProjectItemAdded -= ProjectItemAdded;
ProjectService.ProjectAdded -= ProjectAdded;
ProjectService.SolutionFolderRemoved -= SolutionFolderRemoved;
ProjectService.SolutionClosed -= SolutionClosed;
SD.ParserService.LoadSolutionProjectsThread.Finished -= LoadSolutionProjectsThreadFinished;
}
testService.OpenSolutionChanged -= testService_OpenSolutionChanged;
base.Dispose();
}
// public TestTreeView TestTreeView {
// get { return treeView; }
// }
// public void ResetTestResults()
// {
// treeView.ResetTestResults();
// }
//
public IProject[] GetProjects()
{
return testSolution.TestableProjects.Select(tp => tp.Project).ToArray();
public override object Control {
get { return panel; }
}
// public TestProject GetTestProject(IProject project)
// {
// return treeView.GetTestProject(project);
// }
/// <summary>
/// Updates the state of the buttons on the Unit Tests pad's
/// toolbar.
/// </summary>
public void UpdateToolbar()
void testService_OpenSolutionChanged(object sender, EventArgs e)
{
// ToolbarService.UpdateToolbar(toolBar);
}
/// <summary>
/// Collapses all nodes.
/// </summary>
// public void CollapseAll()
// {
// if (treeView == null || treeView.Nodes == null || treeView.Nodes.Count == 0)
// return;
//
// treeView.CollapseAll();
// }
/// <summary>
/// Called when a solution has been closed.
/// </summary>
// protected void SolutionClosed()
// {
// treeView.Clear();
// }
//
// protected void SolutionFolderRemoved(ISolutionFolder solutionFolder)
// {
// treeView.RemoveSolutionFolder(solutionFolder);
// }
/// <summary>
/// If the project item removed is a reference to a unit
/// test framework then the project will be removed from the
/// test tree.
/// </summary>
// protected void ProjectItemRemoved(ProjectItem projectItem)
// {
// treeView.ProjectItemRemoved(projectItem);
// }
//
// protected void ProjectItemAdded(ProjectItem projectItem)
// {
// treeView.ProjectItemAdded(projectItem);
// }
/// <summary>
/// Protected method so we can test this method.
/// </summary>
protected void UpdateParseInfo(IUnresolvedFile oldFile, IUnresolvedFile newFile)
{
RootUnitTestNode root = (RootUnitTestNode)treeView.Root;
if (root == null) {
// SolutionLoaded(GetOpenSolution());
root = (RootUnitTestNode)treeView.Root;
if (root == null) return;
}
var solution = GetOpenSolution();
if (solution == null)
return;
var project = solution.FindProjectContainingFile((oldFile ?? newFile).FileName);
if (project == null)
return;
var projectNode = root.Children.OfType<ProjectUnitTestNode>().FirstOrDefault(node => node.Project == project);
treeView.TestSolution = testService.OpenSolution;
}
/// <summary>
@ -187,107 +81,5 @@ namespace ICSharpCode.UnitTesting @@ -187,107 +81,5 @@ namespace ICSharpCode.UnitTesting
{
return MenuService.CreateContextMenu(treeView, name);
}
// /// <summary>
// /// Virtual method so we can override this method and return
// /// a dummy TestTreeView when testing.
// /// </summary>
// protected virtual SharpTreeView CreateTestTreeView(IRegisteredTestFrameworks testFrameworks)
// {
// return new SharpTreeView();
// }
/// <summary>
/// Gets the currently open solution.
/// </summary>
protected virtual Solution GetOpenSolution()
{
return ProjectService.OpenSolution;
}
/// <summary>
/// Determines whether the parser is currently still loading the
/// solution.
/// </summary>
protected virtual bool IsParserLoadingSolution {
get { return SD.ParserService.LoadSolutionProjectsThread.IsRunning; }
}
/// <summary>
/// Indicates that an event handler for the ParserService's
/// LoadSolutionProjectsThreadEnded event has been added
/// </summary>
protected virtual void OnAddedLoadSolutionProjectsThreadEndedHandler()
{
}
void SolutionClosed(object source, EventArgs e)
{
// SolutionClosed();
UpdateToolbar();
}
void SolutionFolderRemoved(object source, SolutionFolderEventArgs e)
{
// SolutionFolderRemoved(e.SolutionFolder);
UpdateToolbar();
}
void ProjectAdded(object source, ProjectEventArgs e)
{
UpdateToolbar();
}
void LoadSolutionProjectsThreadFinished(object source, EventArgs e)
{
WorkbenchSingleton.SafeThreadAsyncCall(UpdateToolbar);
Solution solution = ProjectService.OpenSolution;
// WorkbenchSingleton.SafeThreadAsyncCall(SolutionLoaded, solution);
}
// void TestTreeViewKeyPress(object source, KeyPressEventArgs e)
// {
// if (e.KeyChar == '\r') {
// e.Handled = true;
// GotoDefinition();
// } else if (e.KeyChar == ' ') {
// e.Handled = true;
// RunTests();
// }
// }
void GotoDefinition()
{
// RunCommand(new GotoDefinitionCommand());
}
void RunTests()
{
// RunCommand(new RunTestInPadCommand());
}
void RunCommand(ICommand command)
{
command.Owner = treeView;
command.Run();
}
void ProjectItemAdded(object source, ProjectItemEventArgs e)
{
// ProjectItemAdded(e.ProjectItem);
}
void ProjectItemRemoved(object source, ProjectItemEventArgs e)
{
// ProjectItemRemoved(e.ProjectItem);
}
public void ResetTestResults()
{
foreach (var testProject in testSolution.TestableProjects)
testProject.ResetTestResults();
}
}
}

3
src/AddIns/Analysis/UnitTesting/TestRunner/ITestRunner.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using ICSharpCode.SharpDevelop.Util;
namespace ICSharpCode.UnitTesting
@ -11,7 +12,7 @@ namespace ICSharpCode.UnitTesting @@ -11,7 +12,7 @@ namespace ICSharpCode.UnitTesting
event EventHandler<TestFinishedEventArgs> TestFinished;
event EventHandler AllTestsFinished;
event EventHandler<MessageReceivedEventArgs> MessageReceived;
void Start(SelectedTests selectedTests);
void Start(IEnumerable<ITest> selectedTests);
void Stop();
}
}

91
src/AddIns/Analysis/UnitTesting/TestRunner/SelectedTests.cs

@ -1,91 +0,0 @@ @@ -1,91 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
public class SelectedTests
{
string namespaceFilter;
TestClass c;
TestMember member;
List<IProject> projects = new List<IProject>();
public SelectedTests(IProject project, string namespaceFilter, TestClass c, TestMember member)
{
this.namespaceFilter = namespaceFilter;
this.c = c;
this.member = member;
if (project != null) {
projects.Add(project);
}
}
public SelectedTests(IProject project)
: this(project, null, null, null)
{
}
public SelectedTests(object owner, IProject[] selectedProjects)
{
IProject project = TestableCondition.GetProject(owner);
if (project != null) {
projects.Add(project);
} else {
projects.AddRange(selectedProjects);
}
TestProject testProject = TestService.Solution.GetTestProject(project);
if (testProject != null) {
member = testProject.GetTestMember(TestableCondition.GetMember(owner));
c = testProject.GetTestClass(TestableCondition.GetClassFromMemberOrCaller(owner));
}
namespaceFilter = TestableCondition.GetNamespace(owner);
}
public bool HasProjects {
get { return projects.Count > 0; }
}
public void RemoveFirstProject()
{
if (HasProjects) {
projects.RemoveAt(0);
}
}
public IEnumerable<IProject> Projects {
get { return projects; }
}
public int ProjectsCount {
get {return projects.Count;}
}
public IProject Project {
get {
if (projects.Count > 0) {
return projects[0];
}
return null;
}
}
public string NamespaceFilter {
get { return namespaceFilter; }
}
public TestClass Class {
get { return c; }
}
public TestMember Member {
get { return member; }
}
}
}

4
src/AddIns/Analysis/UnitTesting/TestRunner/TestDebuggerBase.cs

@ -2,7 +2,9 @@ @@ -2,7 +2,9 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Debugging;
@ -39,7 +41,7 @@ namespace ICSharpCode.UnitTesting @@ -39,7 +41,7 @@ namespace ICSharpCode.UnitTesting
get { return testResultsMonitor; }
}
public override void Start(SelectedTests selectedTests)
public override void Start(IEnumerable<ITest> selectedTests)
{
ProcessStartInfo startInfo = GetProcessStartInfo(selectedTests);
if (IsDebuggerRunning) {

4
src/AddIns/Analysis/UnitTesting/TestRunner/TestProcessRunnerBase.cs

@ -2,7 +2,9 @@ @@ -2,7 +2,9 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Util;
@ -62,7 +64,7 @@ namespace ICSharpCode.UnitTesting @@ -62,7 +64,7 @@ namespace ICSharpCode.UnitTesting
OnMessageReceived(e.Line);
}
public override void Start(SelectedTests selectedTests)
public override void Start(IEnumerable<ITest> selectedTests)
{
ProcessStartInfo startInfo = GetProcessStartInfo(selectedTests);
Start(startInfo);

4
src/AddIns/Analysis/UnitTesting/TestRunner/TestResultTask.cs

@ -16,7 +16,7 @@ namespace ICSharpCode.UnitTesting @@ -16,7 +16,7 @@ namespace ICSharpCode.UnitTesting
{
}
public static SDTask Create(TestResult result, TestProject project)
public static SDTask Create(TestResult result, ITestProject project)
{
TaskType taskType = TaskType.Warning;
FileLineReference lineRef = null;
@ -76,7 +76,7 @@ namespace ICSharpCode.UnitTesting @@ -76,7 +76,7 @@ namespace ICSharpCode.UnitTesting
/// Returns the location of the specified test member in the
/// project being tested.
/// </summary>
static FileLineReference FindTest(string memberName, TestProject testProject)
static FileLineReference FindTest(string memberName, ITestProject testProject)
{
// if (testProject != null) {
// TestMember testMember = testProject.TestClasses.GetTestMember(memberName);

5
src/AddIns/Analysis/UnitTesting/TestRunner/TestRunnerBase.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace ICSharpCode.UnitTesting
@ -12,7 +13,7 @@ namespace ICSharpCode.UnitTesting @@ -12,7 +13,7 @@ namespace ICSharpCode.UnitTesting
{
}
protected virtual ProcessStartInfo GetProcessStartInfo(SelectedTests selectedTests)
protected virtual ProcessStartInfo GetProcessStartInfo(IEnumerable<ITest> selectedTests)
{
return new ProcessStartInfo();
}
@ -63,6 +64,6 @@ namespace ICSharpCode.UnitTesting @@ -63,6 +64,6 @@ namespace ICSharpCode.UnitTesting
public abstract void Dispose();
public abstract void Stop();
public abstract void Start(SelectedTests selectedTests);
public abstract void Start(IEnumerable<ITest> selectedTests);
}
}

2
src/AddIns/Analysis/UnitTesting/TreeView/ClassUnitTestNode.cs

@ -12,7 +12,7 @@ namespace ICSharpCode.UnitTesting @@ -12,7 +12,7 @@ namespace ICSharpCode.UnitTesting
/// <summary>
/// Represents a TestClass in the tree view.
/// </summary>
public class ClassUnitTestNode : UnitTestBaseNode
public class ClassUnitTestNode : UnitTestNode
{
TestClass testClass;

20
src/AddIns/Analysis/UnitTesting/TreeView/ITestTreeView.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Project;
using System;
@ -11,24 +12,13 @@ namespace ICSharpCode.UnitTesting @@ -11,24 +12,13 @@ namespace ICSharpCode.UnitTesting
public interface ITestTreeView
{
/// <summary>
/// Gets the selected member in the test tree view.
/// Gets the test solution that is being displayed in this tree view.
/// </summary>
TestMember SelectedMember {get;}
ITestSolution TestSolution { get; }
/// <summary>
/// Gets the selected class in the test tree view.
/// Gets the selected tests.
/// </summary>
TestClass SelectedClass {get;}
/// <summary>
/// Gets the selected project for the selected node
/// in the test tree view.
/// </summary>
TestProject SelectedProject {get;}
/// <summary>
/// Gets the namespace for the selected namespace node.
/// </summary>
string SelectedNamespace {get;}
IEnumerable<ITest> SelectedTests { get; }
}
}

2
src/AddIns/Analysis/UnitTesting/TreeView/MemberUnitTestNode.cs

@ -10,7 +10,7 @@ using ICSharpCode.TreeView; @@ -10,7 +10,7 @@ using ICSharpCode.TreeView;
namespace ICSharpCode.UnitTesting
{
public class MemberUnitTestNode : UnitTestBaseNode
public class MemberUnitTestNode : UnitTestNode
{
TestMember testMember;

8
src/AddIns/Analysis/UnitTesting/TreeView/NamespaceUnitTestNode.cs

@ -16,7 +16,7 @@ using ICSharpCode.TreeView; @@ -16,7 +16,7 @@ using ICSharpCode.TreeView;
namespace ICSharpCode.UnitTesting
{
public class NamespaceUnitTestNode : UnitTestBaseNode
public class NamespaceUnitTestNode : UnitTestNode
{
readonly string shortName;
readonly string namespaceName;
@ -50,11 +50,11 @@ namespace ICSharpCode.UnitTesting @@ -50,11 +50,11 @@ namespace ICSharpCode.UnitTesting
internal override TestResultType TestResultType {
get {
if (Children.Count == 0) return TestResultType.None;
if (Children.OfType<UnitTestBaseNode>().Any(node => node.TestResultType == TestResultType.Failure))
if (Children.OfType<UnitTestNode>().Any(node => node.TestResultType == TestResultType.Failure))
return TestResultType.Failure;
if (Children.OfType<UnitTestBaseNode>().Any(node => node.TestResultType == TestResultType.None))
if (Children.OfType<UnitTestNode>().Any(node => node.TestResultType == TestResultType.None))
return TestResultType.None;
if (Children.OfType<UnitTestBaseNode>().Any(node => node.TestResultType == TestResultType.Ignored))
if (Children.OfType<UnitTestNode>().Any(node => node.TestResultType == TestResultType.Ignored))
return TestResultType.Ignored;
return TestResultType.Success;
}

10
src/AddIns/Analysis/UnitTesting/TreeView/ProjectUnitTestNode.cs

@ -17,7 +17,7 @@ using ICSharpCode.TreeView; @@ -17,7 +17,7 @@ using ICSharpCode.TreeView;
namespace ICSharpCode.UnitTesting
{
public class ProjectUnitTestNode : UnitTestBaseNode
public class ProjectUnitTestNode : UnitTestNode
{
TestProject project;
@ -47,7 +47,7 @@ namespace ICSharpCode.UnitTesting @@ -47,7 +47,7 @@ namespace ICSharpCode.UnitTesting
case NotifyCollectionChangedAction.Add:
foreach (TestClass c in e.NewItems) {
if (c.Namespace == "<invalid>") continue;
UnitTestBaseNode node = FindOrCreateNamespace(this, project.Project.RootNamespace, c.Namespace);
UnitTestNode node = FindOrCreateNamespace(this, project.Project.RootNamespace, c.Namespace);
node.Children.OrderedInsert(new ClassUnitTestNode(c), NodeTextComparer);
}
break;
@ -70,7 +70,7 @@ namespace ICSharpCode.UnitTesting @@ -70,7 +70,7 @@ namespace ICSharpCode.UnitTesting
}
}
static UnitTestBaseNode FindOrCreateNamespace(UnitTestBaseNode parent, string parentNamespace, string @namespace)
static UnitTestNode FindOrCreateNamespace(UnitTestNode parent, string parentNamespace, string @namespace)
{
if (parentNamespace == @namespace)
return parent;
@ -101,7 +101,7 @@ namespace ICSharpCode.UnitTesting @@ -101,7 +101,7 @@ namespace ICSharpCode.UnitTesting
}
}
static UnitTestBaseNode FindNamespace(UnitTestBaseNode parent, string parentNamespace, string @namespace)
static UnitTestNode FindNamespace(UnitTestNode parent, string parentNamespace, string @namespace)
{
if (parentNamespace == @namespace)
return parent;
@ -120,7 +120,7 @@ namespace ICSharpCode.UnitTesting @@ -120,7 +120,7 @@ namespace ICSharpCode.UnitTesting
Children.Clear();
foreach (var g in project.TestClasses.Select(c => new ClassUnitTestNode(c)).GroupBy(tc => tc.TestClass.Namespace)) {
if (g.Key == "<invalid>") continue;
UnitTestBaseNode node = FindOrCreateNamespace(this, project.Project.RootNamespace, g.Key);
UnitTestNode node = FindOrCreateNamespace(this, project.Project.RootNamespace, g.Key);
node.Children.AddRange(g.OrderBy(NodeTextComparer));
}
}

8
src/AddIns/Analysis/UnitTesting/TreeView/RootUnitTestNode.cs

@ -24,7 +24,7 @@ namespace ICSharpCode.UnitTesting @@ -24,7 +24,7 @@ namespace ICSharpCode.UnitTesting
/// <summary>
/// Description of RootUnitTestNode.
/// </summary>
public class RootUnitTestNode : UnitTestBaseNode
public class RootUnitTestNode : UnitTestNode
{
readonly TestSolution testSolution;
@ -63,11 +63,11 @@ namespace ICSharpCode.UnitTesting @@ -63,11 +63,11 @@ namespace ICSharpCode.UnitTesting
internal override TestResultType TestResultType {
get {
if (Children.Count == 0) return TestResultType.None;
if (Children.OfType<UnitTestBaseNode>().Any(node => node.TestResultType == TestResultType.Failure))
if (Children.OfType<UnitTestNode>().Any(node => node.TestResultType == TestResultType.Failure))
return TestResultType.Failure;
if (Children.OfType<UnitTestBaseNode>().Any(node => node.TestResultType == TestResultType.None))
if (Children.OfType<UnitTestNode>().Any(node => node.TestResultType == TestResultType.None))
return TestResultType.None;
if (Children.OfType<UnitTestBaseNode>().Any(node => node.TestResultType == TestResultType.Ignored))
if (Children.OfType<UnitTestNode>().Any(node => node.TestResultType == TestResultType.Ignored))
return TestResultType.Ignored;
return TestResultType.Success;
}

104
src/AddIns/Analysis/UnitTesting/TreeView/TestTreeView.cs

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
@ -23,100 +24,49 @@ namespace ICSharpCode.UnitTesting @@ -23,100 +24,49 @@ namespace ICSharpCode.UnitTesting
[Flags]
public enum TestTreeViewState {
None = 0,
SourceCodeItemSelected = 1
SupportsGoToDefinition = 1
}
IRegisteredTestFrameworks testFrameworks;
ITestSolution testSolution;
public TestTreeView(IRegisteredTestFrameworks testFrameworks, TestSolution testSolution)
{
this.testFrameworks = testFrameworks;
// Show 'All Tests' root node only if there is more than one test project in the solution
testSolution.TestableProjects.CollectionChanged += delegate { ShowRoot = testSolution.TestableProjects.Count > 1; };
this.Root = new RootUnitTestNode(testSolution);
}
/// <summary>
/// Gets the current state of the test tree view.
/// </summary>
public Enum InternalState {
get {
if (SelectedItem is ClassUnitTestNode || SelectedItem is MemberUnitTestNode)
return TestTreeViewState.SourceCodeItemSelected;
return TestTreeViewState.None;
}
}
bool IsTestProject(IProject project)
{
return testFrameworks.IsTestProject(project);
}
/// <summary>
/// Gets the member of the currently selected tree node.
/// </summary>
public TestMember SelectedMember {
get {
MemberUnitTestNode memberNode = SelectedItem as MemberUnitTestNode;
if (memberNode != null) {
return memberNode.TestMember;
}
return null;
}
}
/// <summary>
/// Gets the class of the currently selected tree node.
/// </summary>
public TestClass SelectedClass {
get {
ClassUnitTestNode classNode = SelectedItem as ClassUnitTestNode;
if (classNode == null) {
classNode = GetClassNodeFromSelectedMemberNode();
public ITestSolution TestSolution {
get { return testSolution; }
set {
if (testSolution == value)
return;
testSolution = value;
if (testSolution != null) {
this.Root = new UnitTestNode(testSolution);
this.Root.Children.CollectionChanged += delegate {
this.ShowRoot = this.Root != null && this.Root.Children.Count > 1;
};
} else {
this.Root = null;
}
if (classNode != null) {
return classNode.TestClass;
}
return null;
}
}
ClassUnitTestNode GetClassNodeFromSelectedMemberNode()
public TestTreeView()
{
MemberUnitTestNode memberNode = SelectedItem as MemberUnitTestNode;
if (memberNode != null) {
return memberNode.Parent as ClassUnitTestNode;
}
return null;
this.ShowRoot = false;
}
/// <summary>
/// If a namespace node is selected then the fully qualified namespace
/// for this node is returned (i.e. includes the parent namespace prefixed
/// to it). For all other nodes this returns null.
/// Gets the current state of the test tree view.
/// </summary>
public string SelectedNamespace {
public Enum InternalState {
get {
NamespaceUnitTestNode selectedNode = SelectedItem as NamespaceUnitTestNode;
if (selectedNode != null) {
return selectedNode.NamespaceName;
}
return null;
var node = SelectedItem as UnitTestNode;
if (node != null && node.Test.SupportsGoToDefinition)
return TestTreeViewState.SupportsGoToDefinition;
else
return TestTreeViewState.None;
}
}
/// <summary>
/// Gets the selected test project.
/// </summary>
public TestProject SelectedProject {
public IEnumerable<ITest> SelectedTests {
get {
for (var node = SelectedItem as SharpTreeNode; node != null; node = node.Parent) {
var projectNode = node as ProjectUnitTestNode;
if (projectNode != null)
return projectNode.Project;
}
return null;
return this.GetTopLevelSelection().OfType<UnitTestNode>().Select(n => n.Test);
}
}
}

38
src/AddIns/Analysis/UnitTesting/TreeView/UnitTestBaseNode.cs

@ -1,38 +0,0 @@ @@ -1,38 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.TreeView;
namespace ICSharpCode.UnitTesting
{
public abstract class UnitTestBaseNode : SharpTreeNode
{
protected static readonly KeyComparer<SharpTreeNode, string> NodeTextComparer = KeyComparer.Create((SharpTreeNode n) => n.Text.ToString(), StringComparer.OrdinalIgnoreCase, StringComparer.OrdinalIgnoreCase);
internal abstract TestResultType TestResultType { get; }
public override object Icon {
get { return GetIcon(TestResultType); }
}
object GetIcon(TestResultType testResultType)
{
switch (testResultType) {
case TestResultType.None:
return Images.Grey;
case TestResultType.Success:
return Images.Green;
case TestResultType.Failure:
return Images.Red;
case TestResultType.Ignored:
return Images.Yellow;
default:
throw new Exception("Invalid value for TestResultType");
}
}
}
}

128
src/AddIns/Analysis/UnitTesting/TreeView/UnitTestNode.cs

@ -0,0 +1,128 @@ @@ -0,0 +1,128 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.SharpDevelop;
using ICSharpCode.TreeView;
namespace ICSharpCode.UnitTesting
{
public class UnitTestNode : SharpTreeNode
{
protected static readonly IComparer<SharpTreeNode> NodeTextComparer = KeyComparer.Create((SharpTreeNode n) => n.Text.ToString(), StringComparer.OrdinalIgnoreCase, StringComparer.OrdinalIgnoreCase);
readonly ITest test;
public UnitTestNode(ITest test)
{
if (test == null)
throw new ArgumentNullException("test");
this.test = test;
test.DisplayNameChanged += test_NameChanged;
test.ResultChanged += test_ResultChanged;
LazyLoading = true;
}
void DetachEventHandlers()
{
test.DisplayNameChanged -= test_NameChanged;
test.ResultChanged -= test_ResultChanged;
// If children loaded, also detach the collection change event handler
if (!LazyLoading) {
test.NestedTests.CollectionChanged -= test_NestedTests_CollectionChanged;
}
}
public ITest Test {
get { return test; }
}
#region Manage Children
protected override void LoadChildren()
{
Children.Clear();
InsertNestedTests(test.NestedTests);
test.NestedTests.CollectionChanged += test_NestedTests_CollectionChanged;
}
void InsertNestedTests(IEnumerable<ITest> nestedTests)
{
foreach (var test in nestedTests) {
Children.OrderedInsert(test.CreateTreeNode(), NodeTextComparer);
}
}
void test_NestedTests_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (!IsVisible) {
SwitchBackToLazyLoading();
return;
}
switch (e.Action) {
case NotifyCollectionChangedAction.Add:
InsertNestedTests(e.NewItems.Cast<ITest>());
break;
case NotifyCollectionChangedAction.Remove:
Children.RemoveAll(n => e.OldItems.Contains(((UnitTestNode)n).Test));
break;
case NotifyCollectionChangedAction.Reset:
if (IsExpanded) {
Children.Clear();
InsertNestedTests(test.NestedTests);
} else {
SwitchBackToLazyLoading();
}
break;
default:
throw new NotSupportedException("Invalid value for NotifyCollectionChangedAction");
}
}
void SwitchBackToLazyLoading()
{
test.NestedTests.CollectionChanged -= test_NestedTests_CollectionChanged;
Children.Clear();
LazyLoading = true;
}
#endregion
#region Icon + Text
public override object Icon {
get {
switch (test.Result) {
case TestResultType.None:
return Images.Grey;
case TestResultType.Success:
return Images.Green;
case TestResultType.Failure:
return Images.Red;
case TestResultType.Ignored:
return Images.Yellow;
default:
throw new NotSupportedException("Invalid value for TestResultType");
}
}
}
void test_ResultChanged(object sender, EventArgs e)
{
RaisePropertyChanged("Icon");
RaisePropertyChanged("ExpandedIcon");
}
public override object Text {
get { return test.DisplayName; }
}
void test_NameChanged(object sender, EventArgs e)
{
RaisePropertyChanged("Text");
}
#endregion
}
}

21
src/AddIns/Analysis/UnitTesting/UnitTesting.addin

@ -17,6 +17,11 @@ @@ -17,6 +17,11 @@
</Import>
</Runtime>
<Path name = "/SharpDevelop/Services">
<Service id="ICSharpCode.UnitTesting.ITestService"
class="ICSharpCode.UnitTesting.SDTestService"/>
</Path>
<Path name="/SharpDevelop/UnitTesting/TestFrameworks">
<TestFramework id="nunit"
class="ICSharpCode.UnitTesting.NUnitTestFramework"
@ -45,7 +50,7 @@ @@ -45,7 +50,7 @@
<MenuItem id="RunInPad"
label="${res:ICSharpCode.UnitTesting.RunInTestPad}"
icon="PadIcons.NUnitTest"
class="ICSharpCode.UnitTesting.RunTestInPadCommand"/>
class="ICSharpCode.UnitTesting.RunSelectedTestCommand"/>
</ComplexCondition>
<Include id="CommonTestCommands" path="/SharpDevelop/Pads/UnitTestsPad/CommonTestCommands"/>
</MenuItem>
@ -63,7 +68,7 @@ @@ -63,7 +68,7 @@
<MenuItem id="RunWithDebugger"
label="${res:ICSharpCode.UnitTesting.RunWithDebugger}"
icon="Icons.16x16.RunProgramIcon"
class="ICSharpCode.UnitTesting.RunTestWithDebuggerCommand"/>
class="ICSharpCode.UnitTesting.RunSelectedTestWithDebuggerCommand"/>
</ComplexCondition>
</Path>
@ -78,12 +83,12 @@ @@ -78,12 +83,12 @@
<ToolbarItem id="RunAll"
icon="Icons.16x16.RunAllIcon"
tooltip="${res:NUnitPad.NUnitPadContent.RunAllTests}"
class="ICSharpCode.UnitTesting.RunAllTestsInPadCommand"/>
class="ICSharpCode.UnitTesting.RunAllTestsInSolutionCommand"/>
<ToolbarItem id="Run"
insertafter="RunAll"
icon="Icons.16x16.RunProgramIcon"
tooltip="${res:NUnitPad.NUnitPadContent.RunItem}"
class="ICSharpCode.UnitTesting.RunTestInPadCommand"/>
class="ICSharpCode.UnitTesting.RunSelectedTestCommand"/>
</ComplexCondition>
<ComplexCondition action="Disable">
<And>
@ -120,7 +125,7 @@ @@ -120,7 +125,7 @@
<MenuItem id="Run"
icon="Icons.16x16.RunProgramIcon"
label="${res:NUnitPad.NUnitPadContent.RunTestsContextMenuLabel}"
class="ICSharpCode.UnitTesting.RunTestInPadCommand"/>
class="ICSharpCode.UnitTesting.RunSelectedTestCommand"/>
</ComplexCondition>
<Include id="CommonTestCommands" path="/SharpDevelop/Pads/UnitTestsPad/CommonTestCommands"/>
<ComplexCondition action="Disable">
@ -133,7 +138,7 @@ @@ -133,7 +138,7 @@
label="${res:NUnitPad.NUnitPadContent.StopTests}"
class="ICSharpCode.UnitTesting.StopTestsCommand"/>
</ComplexCondition>
<Condition name="Ownerstate" ownerstate="SourceCodeItemSelected" action="Disable">
<Condition name="Ownerstate" ownerstate="SupportsGoToDefinition" action="Disable">
<MenuItem id="GotoDefinition"
label="${res:NUnitPad.NUnitPadContent.GotoDefinitionContextMenuLabel}"
class="ICSharpCode.UnitTesting.GotoDefinitionCommand"/>
@ -152,7 +157,7 @@ @@ -152,7 +157,7 @@
<MenuItem id="RunAll"
icon="Icons.16x16.RunAllIcon"
label="${res:NUnitPad.NUnitPadContent.RunAllTests}"
class="ICSharpCode.UnitTesting.RunAllTestsInPadCommand"/>
class="ICSharpCode.UnitTesting.RunAllTestsInSolutionCommand"/>
</ComplexCondition>
<ComplexCondition action="Disable">
<And>
@ -165,7 +170,7 @@ @@ -165,7 +170,7 @@
<MenuItem id="RunProjectTests"
icon="Icons.16x16.RunProgramIcon"
label="${res:ICSharpCode.UnitTesting.RunProjectTests}"
class="ICSharpCode.UnitTesting.RunProjectTestsInPadCommand"/>
class="ICSharpCode.UnitTesting.RunAllTestsInProjectCommand"/>
</ComplexCondition>
<ComplexCondition action="Disable">
<And>

56
src/AddIns/Analysis/UnitTesting/UnitTesting.csproj

@ -66,79 +66,54 @@ @@ -66,79 +66,54 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Commands\AbstractRunTestCommand.cs" />
<Compile Include="Commands\IRunTestCommandContext.cs" />
<Compile Include="Commands\MultipleProjectBuildable.cs" />
<Compile Include="Commands\RunAllTestsInPadCommand.cs" />
<Compile Include="Commands\PadCommands.cs" />
<Compile Include="Commands\RunningTestsCondition.cs" />
<Compile Include="Commands\RunProjectTestsInPadCommand.cs" />
<Compile Include="Commands\RunTestCommandContext.cs" />
<Compile Include="Commands\RunTestInPadCommand.cs" />
<Compile Include="Commands\RunTestWithDebuggerCommand.cs" />
<Compile Include="Commands\TestableCondition.cs" />
<Compile Include="Commands\UnitTestCommands.cs" />
<Compile Include="Frameworks\ITestService.cs" />
<Compile Include="Frameworks\TestExecutionManager.cs" />
<Compile Include="Frameworks\TestExecutionOptions.cs" />
<Compile Include="Interfaces\IUnitTestProcessRunner.cs" />
<Compile Include="Interfaces\UnitTestProcessRunner.cs" />
<Compile Include="TestRunner\ITestRunner.cs" />
<Compile Include="TestRunner\TestResultsMonitor.cs" />
<Compile Include="TestRunner\TestResultsReader.cs" />
<Compile Include="TestRunner\TestResultTask.cs" />
<Compile Include="Frameworks\IRegisteredTestFrameworks.cs" />
<Compile Include="Model\ITest.cs" />
<Compile Include="Model\ITestProject.cs" />
<Compile Include="Model\ITestSolution.cs" />
<Compile Include="Model\TestBase.cs" />
<Compile Include="Frameworks\ITestFramework.cs" />
<Compile Include="Frameworks\ITestFrameworkFactory.cs" />
<Compile Include="Interfaces\IBuildOptions.cs" />
<Compile Include="Interfaces\IBuildProjectFactory.cs" />
<Compile Include="Interfaces\IFileSystem.cs" />
<Compile Include="Interfaces\IUnitTestDebuggerService.cs" />
<Compile Include="Interfaces\IUnitTestSaveAllFilesCommand.cs" />
<Compile Include="Interfaces\IUnitTestTaskService.cs" />
<Compile Include="Interfaces\IUnitTestWorkbench.cs" />
<Compile Include="Interfaces\UnitTestBuildOptions.cs" />
<Compile Include="Model\TestCollection.cs" />
<Compile Include="Model\TestNamespace.cs" />
<Compile Include="Model\TestProjectBase.cs" />
<Compile Include="Model\TestResult.cs" />
<Compile Include="Pad\EmptyUnitTestsPad.cs" />
<Compile Include="Pad\IUnitTestsPad.cs" />
<Compile Include="Model\TestResultTypeChangedEventArgs.cs" />
<Compile Include="NUnit\NUnitTestProject.cs" />
<Compile Include="Pad\UnitTestsPad.cs" />
<Compile Include="Interfaces\UnitTestBuildProjectFactory.cs" />
<Compile Include="Interfaces\UnitTestDebuggerService.cs" />
<Compile Include="Interfaces\UnitTestFileService.cs" />
<Compile Include="Interfaces\UnitTestSaveAllFilesCommand.cs" />
<Compile Include="Interfaces\UnitTestTaskService.cs" />
<Compile Include="Interfaces\UnitTestWorkbench.cs" />
<Compile Include="Model\TestClass.cs" />
<Compile Include="Model\TestMember.cs" />
<Compile Include="Model\TestProject.cs" />
<Compile Include="Model\TestSolution.cs" />
<Compile Include="Frameworks\ITestResultsMonitor.cs" />
<Compile Include="Frameworks\RegisteredTestFrameworks.cs" />
<Compile Include="Frameworks\TestFrameworkDescriptor.cs" />
<Compile Include="Frameworks\TestFrameworkDoozer.cs" />
<Compile Include="Frameworks\TestFrameworkFactory.cs" />
<Compile Include="Frameworks\TestService.cs" />
<Compile Include="TreeView\ClassUnitTestNode.cs" />
<Compile Include="Frameworks\SDTestService.cs" />
<Compile Include="TreeView\ITestTreeView.cs" />
<Compile Include="TreeView\MemberUnitTestNode.cs" />
<Compile Include="TreeView\NamespaceUnitTestNode.cs" />
<Compile Include="TreeView\ProjectUnitTestNode.cs" />
<Compile Include="TreeView\RootUnitTestNode.cs" />
<Compile Include="TreeView\TestTreeView.cs" />
<Compile Include="TreeView\UnitTestBaseNode.cs" />
<Compile Include="TreeView\UnitTestNode.cs" />
<Compile Include="NUnit\NUnitConsoleApplication.cs" />
<Compile Include="NUnit\NUnitTestDebugger.cs" />
<Compile Include="NUnit\NUnitTestFramework.cs" />
<Compile Include="NUnit\NUnitTestResult.cs" />
<Compile Include="NUnit\NUnitTestRunner.cs" />
<Compile Include="Options\UnitTestingOptions.cs" />
<Compile Include="Options\UnitTestingOptionsPanel.xaml.cs">
<DependentUpon>UnitTestingOptionsPanel.xaml</DependentUpon>
</Compile>
<Compile Include="Resources\Images.cs" />
<Compile Include="TestRunner\MessageReceivedEventArgs.cs" />
<Compile Include="TestRunner\SelectedTests.cs" />
<Compile Include="TestRunner\TestDebuggerBase.cs" />
<Compile Include="TestRunner\TestFinishedEventArgs.cs" />
<Compile Include="TestRunner\TestProcessRunnerBase.cs" />
<Compile Include="TestRunner\TestProcessRunnerBaseContext.cs" />
<Compile Include="TestRunner\TestRunnerBase.cs" />
<None Include="PostBuildEvent.proj" />
<None Include="UnitTesting.addin">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
@ -197,7 +172,6 @@ @@ -197,7 +172,6 @@
<Folder Include="Model" />
<Folder Include="Options" />
<Folder Include="NUnit" />
<Folder Include="TestRunner" />
<Folder Include="TreeView" />
</ItemGroup>
<ItemGroup>

20
src/Libraries/NRefactory/ICSharpCode.NRefactory/Utils/MultiDictionary.cs

@ -62,6 +62,15 @@ namespace ICSharpCode.NRefactory.Utils @@ -62,6 +62,15 @@ namespace ICSharpCode.NRefactory.Utils
return false;
}
/// <summary>
/// Removes all entries with the specified key.
/// </summary>
/// <returns>Returns true if at least one entry was removed.</returns>
public bool RemoveAll(TKey key)
{
return dict.Remove(key);
}
public void Clear()
{
dict.Clear();
@ -81,10 +90,21 @@ namespace ICSharpCode.NRefactory.Utils @@ -81,10 +90,21 @@ namespace ICSharpCode.NRefactory.Utils
}
}
/// <summary>
/// Returns the number of different keys.
/// </summary>
public int Count {
get { return dict.Count; }
}
public ICollection<TKey> Keys {
get { return dict.Keys; }
}
public IEnumerable<TValue> Values {
get { return dict.Values.SelectMany(list => list); }
}
IEnumerable<TValue> ILookup<TKey, TValue>.this[TKey key] {
get { return this[key]; }
}

1
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -372,6 +372,7 @@ @@ -372,6 +372,7 @@
<Compile Include="Src\Project\MSBuildEngine\WorkerProcess.cs" />
<Compile Include="Src\Project\MSBuildFileProject.cs" />
<Compile Include="Src\Project\MSBuildItemWrapper.cs" />
<Compile Include="Src\Project\MultipleProjectBuildable.cs" />
<Compile Include="Src\Project\PortableLibrary\CheckPortableLibraryInstalled.cs" />
<Compile Include="Src\Project\PortableLibrary\ConvertToPortableLibraryProjectBehavior.cs" />
<Compile Include="Src\Project\PortableLibrary\PickPortableTargetFramework.cs" />

23
src/Main/Base/Project/Src/Commands/BuildCommands.cs

@ -3,9 +3,10 @@ @@ -3,9 +3,10 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using ICSharpCode.Core;
using ICSharpCode.Core.Presentation;
using ICSharpCode.SharpDevelop.Debugging;
@ -76,6 +77,26 @@ namespace ICSharpCode.SharpDevelop.Project.Commands @@ -76,6 +77,26 @@ namespace ICSharpCode.SharpDevelop.Project.Commands
}
}
public Task<BuildResults> BuildAsync(CancellationToken cancellationToken)
{
var registration = cancellationToken.Register(BuildEngine.CancelGuiBuild, true);
var tcs = new TaskCompletionSource<BuildResults>();
this.BuildComplete += delegate {
registration.Dispose();
if (cancellationToken.IsCancellationRequested)
tcs.TrySetCanceled();
else
tcs.TrySetResult(this.LastBuildResults);
};
try {
StartBuild();
} catch (Exception ex) {
registration.Dispose();
tcs.TrySetException(ex);
}
return tcs.Task;
}
/// <summary>
/// Notifies the user that #develp's internal MSBuildEngine
/// implementation only supports compiling solutions and projects;

4
src/AddIns/Analysis/UnitTesting/Commands/MultipleProjectBuildable.cs → src/Main/Base/Project/Src/Project/MultipleProjectBuildable.cs

@ -6,7 +6,7 @@ using System.Collections.Generic; @@ -6,7 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
namespace ICSharpCode.SharpDevelop.Project
{
/// <summary>
/// IBuildable implementation that builds several projects.
@ -17,7 +17,7 @@ namespace ICSharpCode.UnitTesting @@ -17,7 +17,7 @@ namespace ICSharpCode.UnitTesting
public MultipleProjectBuildable(IEnumerable<IBuildable> projects)
{
this.projects = projects.ToArray();
this.projects = projects.Where(p => p != null).ToArray();
}
public string Name {

22
src/Main/Base/Project/Src/Services/Tasks/TaskService.cs

@ -110,10 +110,16 @@ namespace ICSharpCode.SharpDevelop @@ -110,10 +110,16 @@ namespace ICSharpCode.SharpDevelop
public static void ClearExceptCommentTasks()
{
List<SDTask> commentTasks = new List<SDTask>(CommentTasks);
Clear();
foreach (SDTask t in commentTasks) {
Add(t);
bool wasInUpdate = InUpdate;
InUpdate = true;
try {
List<SDTask> commentTasks = new List<SDTask>(CommentTasks);
Clear();
foreach (SDTask t in commentTasks) {
Add(t);
}
} finally {
InUpdate = wasInUpdate;
}
}
@ -149,10 +155,10 @@ namespace ICSharpCode.SharpDevelop @@ -149,10 +155,10 @@ namespace ICSharpCode.SharpDevelop
List<SDTask> newTasks = new List<SDTask>();
foreach (TagComment tag in tagComments) {
newTasks.Add(new SDTask(fileName,
tag.Key + tag.CommentString,
tag.Region.BeginColumn,
tag.Region.BeginLine,
TaskType.Comment));
tag.Key + tag.CommentString,
tag.Region.BeginColumn,
tag.Region.BeginLine,
TaskType.Comment));
}
List<SDTask> oldTasks = new List<SDTask>();

Loading…
Cancel
Save