Browse Source

UnitTesting: use ITestFramework, clean-up.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
f0b7f5805e
  1. 4
      src/AddIns/Analysis/UnitTesting/Commands/RunProjectTestsInPadCommand.cs
  2. 546
      src/AddIns/Analysis/UnitTesting/Commands/RunTestCommands.cs
  3. 45
      src/AddIns/Analysis/UnitTesting/Commands/UnitTestCommands.cs
  4. 72
      src/AddIns/Analysis/UnitTesting/Extensions.cs
  5. 15
      src/AddIns/Analysis/UnitTesting/Gui/UnitTestsPad.cs
  6. 12
      src/AddIns/Analysis/UnitTesting/Implementation/UnitTestFileService.cs
  7. 7
      src/AddIns/Analysis/UnitTesting/Interfaces/IRegisteredTestFrameworks.cs
  8. 7
      src/AddIns/Analysis/UnitTesting/Interfaces/ITestFramework.cs
  9. 2
      src/AddIns/Analysis/UnitTesting/Interfaces/ITestTreeView.cs
  10. 13
      src/AddIns/Analysis/UnitTesting/Interfaces/IUnitTestFileService.cs
  11. 49
      src/AddIns/Analysis/UnitTesting/Model/TestClass.cs
  12. 27
      src/AddIns/Analysis/UnitTesting/Model/TestMember.cs
  13. 118
      src/AddIns/Analysis/UnitTesting/Model/TestProject.cs
  14. 157
      src/AddIns/Analysis/UnitTesting/Model/TestSolution.cs
  15. 4
      src/AddIns/Analysis/UnitTesting/NUnit/NUnitConsoleApplication.cs
  16. 35
      src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestFramework.cs
  17. 10
      src/AddIns/Analysis/UnitTesting/Nodes/ClassUnitTestNode.cs
  18. 4
      src/AddIns/Analysis/UnitTesting/Nodes/MemberUnitTestNode.cs
  19. 10
      src/AddIns/Analysis/UnitTesting/Nodes/ProjectUnitTestNode.cs
  20. 13
      src/AddIns/Analysis/UnitTesting/Nodes/RootUnitTestNode.cs
  21. 4
      src/AddIns/Analysis/UnitTesting/Nodes/UnitTestBaseNode.cs
  22. 50
      src/AddIns/Analysis/UnitTesting/Service/RegisteredTestFrameworks.cs
  23. 31
      src/AddIns/Analysis/UnitTesting/Service/SelectedTests.cs
  24. 82
      src/AddIns/Analysis/UnitTesting/Service/TestService.cs
  25. 20
      src/AddIns/Analysis/UnitTesting/Service/TestableCondition.cs
  26. 102
      src/AddIns/Analysis/UnitTesting/Src/AllTestsTreeNode.cs
  27. 53
      src/AddIns/Analysis/UnitTesting/Src/EmptyUnitTestsPad.cs
  28. 23
      src/AddIns/Analysis/UnitTesting/Src/MessageReceivedEventArgs.cs
  29. 47
      src/AddIns/Analysis/UnitTesting/Src/MultipleProjectBuildable.cs
  30. 26
      src/AddIns/Analysis/UnitTesting/Src/RunAllTestsInPadCommand.cs
  31. 546
      src/AddIns/Analysis/UnitTesting/Src/RunTestCommands.cs
  32. 26
      src/AddIns/Analysis/UnitTesting/Src/RunTestInPadCommand.cs
  33. 26
      src/AddIns/Analysis/UnitTesting/Src/RunTestWithDebuggerCommand.cs
  34. 19
      src/AddIns/Analysis/UnitTesting/Src/RunningTestsCondition.cs
  35. 214
      src/AddIns/Analysis/UnitTesting/Src/TestClassCollection.cs
  36. 30
      src/AddIns/Analysis/UnitTesting/Src/TestClassEventArgs.cs
  37. 108
      src/AddIns/Analysis/UnitTesting/Src/TestDebuggerBase.cs
  38. 23
      src/AddIns/Analysis/UnitTesting/Src/TestFinishedEventArgs.cs
  39. 90
      src/AddIns/Analysis/UnitTesting/Src/TestFrameworkDescriptor.cs
  40. 30
      src/AddIns/Analysis/UnitTesting/Src/TestFrameworkDoozer.cs
  41. 23
      src/AddIns/Analysis/UnitTesting/Src/TestFrameworkFactory.cs
  42. 153
      src/AddIns/Analysis/UnitTesting/Src/TestMemberCollection.cs
  43. 30
      src/AddIns/Analysis/UnitTesting/Src/TestMemberEventArgs.cs
  44. 55
      src/AddIns/Analysis/UnitTesting/Src/TestMethodTreeNode.cs
  45. 109
      src/AddIns/Analysis/UnitTesting/Src/TestProcessRunnerBase.cs
  46. 52
      src/AddIns/Analysis/UnitTesting/Src/TestProcessRunnerBaseContext.cs
  47. 178
      src/AddIns/Analysis/UnitTesting/Src/TestResultsMonitor.cs
  48. 155
      src/AddIns/Analysis/UnitTesting/Src/TestResultsReader.cs
  49. 68
      src/AddIns/Analysis/UnitTesting/Src/TestRunnerBase.cs
  50. 47
      src/AddIns/Analysis/UnitTesting/Src/TestService.cs
  51. 17
      src/AddIns/Analysis/UnitTesting/Src/UnitTestAddInTree.cs
  52. 221
      src/AddIns/Analysis/UnitTesting/Src/UnitTestApplicationStartHelper.cs
  53. 15
      src/AddIns/Analysis/UnitTesting/Src/UnitTestBuildOptions.cs
  54. 18
      src/AddIns/Analysis/UnitTesting/Src/UnitTestBuildProjectFactory.cs
  55. 19
      src/AddIns/Analysis/UnitTesting/Src/UnitTestDebuggerService.cs
  56. 27
      src/AddIns/Analysis/UnitTesting/Src/UnitTestFileService.cs
  57. 24
      src/AddIns/Analysis/UnitTesting/Src/UnitTestMessageService.cs
  58. 58
      src/AddIns/Analysis/UnitTesting/Src/UnitTestProcessRunner.cs
  59. 15
      src/AddIns/Analysis/UnitTesting/Src/UnitTestSaveAllFilesCommand.cs
  60. 27
      src/AddIns/Analysis/UnitTesting/Src/UnitTestWorkbench.cs
  61. 13
      src/AddIns/Analysis/UnitTesting/TestTreeView.cs
  62. 220
      src/AddIns/Analysis/UnitTesting/UnitTestApplicationStartHelper.cs
  63. 10
      src/AddIns/Analysis/UnitTesting/UnitTesting.csproj
  64. 2
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs
  65. 4
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs
  66. 2
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/DiffControl.xaml.cs
  67. 21
      src/Libraries/NRefactory/ICSharpCode.NRefactory/Utils/KeyComparer.cs
  68. 2
      src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/GacReferencePanel.cs
  69. 4
      src/Main/Base/Project/Src/Services/ParserService/ParseInformationEventArgs.cs
  70. 281
      src/Main/Base/Project/Src/Util/ExtensionMethods.cs

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

@ -23,11 +23,11 @@ namespace ICSharpCode.UnitTesting @@ -23,11 +23,11 @@ namespace ICSharpCode.UnitTesting
base.Run();
}
public IMember SelectedMember {
public TestMember SelectedMember {
get { return null; }
}
public IClass SelectedClass {
public TestClass SelectedClass {
get { return null; }
}

546
src/AddIns/Analysis/UnitTesting/Commands/RunTestCommands.cs

@ -1,546 +0,0 @@ @@ -1,546 +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.Diagnostics;
using System.IO;
using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Commands;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Project.Commands;
using ICSharpCode.SharpDevelop.Util;
namespace ICSharpCode.UnitTesting
{
public abstract class AbstractRunTestCommand : AbstractMenuCommand
{
static MessageViewCategory testRunnerCategory;
static AbstractRunTestCommand runningTestCommand;
List<IProject> projects;
IProject currentProject;
TestResultsMonitor testResultsMonitor;
public AbstractRunTestCommand()
{
testResultsMonitor = new TestResultsMonitor();
testResultsMonitor.TestFinished += TestFinished;
}
/// <summary>
/// Gets the running test command.
/// </summary>
public static AbstractRunTestCommand RunningTestCommand {
get {
return runningTestCommand;
}
}
/// <summary>
/// Gets whether a test is currently running.
/// </summary>
public static bool IsRunningTest {
get {
return runningTestCommand != null;
}
}
public override void Run()
{
projects = new List<IProject>();
IMethod m = TestableCondition.GetMethod(Owner);
ITypeDefinition c = (m != null) ? m.DeclaringType.GetDefinition() : TestableCondition.GetClass(Owner);
IProject project = TestableCondition.GetProject(Owner);
string namespaceFilter = TestableCondition.GetNamespace(Owner);
if (project != null) {
projects.Add(project);
} else if (UnitTestsPad.Instance != null) {
projects.AddRange(UnitTestsPad.Instance.GetProjects());
}
if (projects.Count > 0) {
runningTestCommand = this;
try {
BeforeRun();
if (IsRunningTest) {
currentProject = projects[0];
Run(currentProject, namespaceFilter, c, m);
}
} catch {
runningTestCommand = null;
throw;
}
}
}
public static MessageViewCategory TestRunnerCategory {
get {
if (testRunnerCategory == null) {
MessageViewCategory.Create(ref testRunnerCategory, "UnitTesting", "${res:ICSharpCode.NUnitPad.NUnitPadContent.PadName}");
}
return testRunnerCategory;
}
}
/// <summary>
/// Stops running the tests.
/// </summary>
public void Stop()
{
runningTestCommand = null;
UpdateUnitTestsPadToolbar();
projects.Clear();
testResultsMonitor.Stop();
StopMonitoring();
OnStop();
}
/// <summary>
/// Called before all tests are run. If multiple projects are
/// to be tested this is called only once.
/// </summary>
protected virtual void OnBeforeRunTests()
{
}
/// <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()
{
}
protected abstract void RunTests(UnitTestApplicationStartHelper helper);
/// <summary>
/// Called by derived classes when a single test run
/// is finished.
/// </summary>
protected void TestsFinished()
{
WorkbenchSingleton.AssertMainThread();
// Read the rest of the file just in case.
testResultsMonitor.Stop();
testResultsMonitor.Read();
StopMonitoring();
projects.Remove(currentProject);
if (projects.Count > 0) {
currentProject = projects[0];
Run(currentProject, null, null, null);
} else {
runningTestCommand = null;
UpdateUnitTestsPadToolbar();
if (TaskService.SomethingWentWrong && ErrorListPad.ShowAfterBuild) {
ShowErrorList();
}
OnAfterRunTests();
}
}
/// <summary>
/// Called by derived classes to show a single test result.
/// </summary>
protected void ShowResult(TestResult result)
{
if (result.IsFailure || result.IsIgnored) {
TaskService.Add(CreateTask(result));
}
UpdateTestResult(result);
}
/// <summary>
/// Called when the test run should be stopped.
/// </summary>
protected virtual void OnStop()
{
}
/// <summary>
/// Brings the specified pad to the front.
/// </summary>
protected void ShowPad(PadDescriptor padDescriptor)
{
if (padDescriptor != null) {
WorkbenchSingleton.SafeThreadAsyncCall(padDescriptor.BringPadToFront);
}
}
/// <summary>
/// Runs the tests after building the project under test.
/// </summary>
void Run(IProject project, string namespaceFilter, ITypeDefinition fixture, IMethod test)
{
BuildProjectBeforeTestRun build = new BuildProjectBeforeTestRun(project);
build.BuildComplete += delegate {
OnBuildComplete(build.LastBuildResults, project, namespaceFilter, fixture, test);
};
build.Run();
}
void ShowUnitTestsPad()
{
ShowPad(WorkbenchSingleton.Workbench.GetPad(typeof(UnitTestsPad)));
}
void UpdateUnitTestsPadToolbar()
{
if (UnitTestsPad.Instance != null) {
UnitTestsPad.Instance.UpdateToolbar();
}
}
/// <summary>
/// Sets the initial workbench state before starting
/// a test run.
/// </summary>
void BeforeRun()
{
TaskService.BuildMessageViewCategory.ClearText();
TaskService.InUpdate = true;
TaskService.ClearExceptCommentTasks();
TaskService.InUpdate = false;
TestRunnerCategory.ClearText();
ShowUnitTestsPad();
ShowOutputPad();
UpdateUnitTestsPadToolbar();
ResetAllTestResults();
OnBeforeRunTests();
}
/// <summary>
/// Brings output pad to the front.
/// </summary>
void ShowOutputPad()
{
ShowPad(WorkbenchSingleton.Workbench.GetPad(typeof(CompilerMessageView)));
}
SDTask CreateTask(TestResult result)
{
TaskType taskType = TaskType.Warning;
FileLineReference lineRef = null;
string message = String.Empty;
if (result.IsFailure) {
taskType = TaskType.Error;
lineRef = OutputTextLineParser.GetNUnitOutputFileLineReference(result.StackTrace, true);
message = GetTestResultMessage(result, "${res:NUnitPad.NUnitPadContent.TestTreeView.TestFailedMessage}");
} else if (result.IsIgnored) {
message = GetTestResultMessage(result, "${res:NUnitPad.NUnitPadContent.TestTreeView.TestNotExecutedMessage}");
}
if (lineRef == null) {
lineRef = FindTest(result.Name);
}
if (lineRef != null) {
return new SDTask(FileName.Create(lineRef.FileName),
message, lineRef.Column, lineRef.Line, taskType);
}
return new SDTask(null, message, 0, 0, taskType);
}
/// <summary>
/// Returns the test result message if there is on otherwise
/// uses the string resource to create a message.
/// </summary>
string GetTestResultMessage(TestResult result, string stringResource)
{
if (result.Message.Length > 0) {
return result.Message;
}
return StringParser.Parse(stringResource, new[] { new StringTagPair("TestCase", result.Name) });
}
/// <summary>
/// Returns the location of the specified test method in the
/// project being tested.
/// </summary>
FileLineReference FindTest(string methodName)
{
TestProject testProject = GetTestProject(currentProject);
if (testProject != null) {
TestMember method = testProject.GetTestMethod(methodName);
if (method != null) {
var filePos = method.Method.Region;
return new FileLineReference(filePos.FileName, filePos.BeginLine, filePos.BeginColumn);
}
}
return null;
}
void ShowErrorList()
{
ShowPad(WorkbenchSingleton.Workbench.GetPad(typeof(ErrorListPad)));
}
/// <summary>
/// Runs the test for the project after a successful build.
/// </summary>
void OnBuildComplete(BuildResults results, IProject project, string namespaceFilter, ITypeDefinition fixture, IMethod test)
{
if (results.ErrorCount == 0 && IsRunningTest) {
UnitTestApplicationStartHelper helper = new UnitTestApplicationStartHelper();
UnitTestingOptions options = UnitTestingOptions.Instance;
helper.NoThread = options.NoThread;
helper.NoLogo = options.NoLogo;
helper.NoDots = options.NoDots;
helper.Labels = options.Labels;
helper.ShadowCopy = !options.NoShadow;
if (options.CreateXmlOutputFile) {
helper.XmlOutputFile = Path.Combine(Path.GetDirectoryName(project.OutputAssemblyFullPath), project.AssemblyName + "-TestResult.xml");
}
helper.Initialize(project, namespaceFilter, fixture, test);
helper.Results = Path.GetTempFileName();
ResetTestResults(project);
testResultsMonitor.FileName = helper.Results;
testResultsMonitor.Start();
try {
RunTests(helper);
} catch {
StopMonitoring();
throw;
}
} else {
if (IsRunningTest) {
Stop();
}
if (TaskService.SomethingWentWrong && ErrorListPad.ShowAfterBuild) {
ShowErrorList();
}
}
}
/// <summary>
/// Clears the test results in the test tree view for the
/// project currently being tested.
/// </summary>
void ResetTestResults(IProject project)
{
TestProject testProject = GetTestProject(project);
if (testProject != null) {
testProject.ResetTestResults();
}
}
/// <summary>
/// Clears the test results in the test tree view for all the
/// displayed projects.
/// </summary>
void ResetAllTestResults()
{
if (UnitTestsPad.Instance != null) {
UnitTestsPad.Instance.ResetTestResults();
}
}
/// <summary>
/// Gets the TestProject associated with the specified project
/// from the test tree view.
/// </summary>
TestProject GetTestProject(IProject project)
{
if (UnitTestsPad.Instance != null) {
return TestService.TestableProjects.FirstOrDefault(tp => tp.Project == project);
}
return null;
}
/// <summary>
/// Updates the test result in the test tree view.
/// </summary>
void UpdateTestResult(TestResult result)
{
TestProject testProject = GetTestProject(currentProject);
if (testProject != null) {
testProject.UpdateTestResult(result);
}
}
void StopMonitoring()
{
try {
File.Delete(testResultsMonitor.FileName);
} catch { }
testResultsMonitor.Dispose();
}
void TestFinished(object source, TestFinishedEventArgs e)
{
WorkbenchSingleton.SafeThreadAsyncCall(ShowResult, e.Result);
}
}
/// <summary>
/// Custom build command that makes sure errors and warnings
/// are not cleared from the Errors list before every build since
/// we may be running multiple tests after each other.
/// </summary>
public class BuildProjectBeforeTestRun : BuildProjectBeforeExecute
{
public BuildProjectBeforeTestRun(IProject targetProject)
: base(targetProject)
{
}
/// <summary>
/// Before a build do not clear the tasks, just save any
/// dirty files.
/// </summary>
public override void BeforeBuild()
{
SaveAllFiles.SaveAll();
}
}
public class RunTestInPadCommand : AbstractRunTestCommand
{
ProcessRunner runner;
public RunTestInPadCommand()
{
runner = new ProcessRunner();
runner.LogStandardOutputAndError = false;
runner.OutputLineReceived += OutputLineReceived;
runner.ProcessExited += ProcessExited;
}
protected override void RunTests(UnitTestApplicationStartHelper helper)
{
TestRunnerCategory.AppendLine(helper.GetCommandLine());
runner.Start(helper.UnitTestApplication, helper.GetArguments());
}
protected override void OnStop()
{
runner.Kill();
}
protected ProcessRunner GetProcessRunner()
{
return runner;
}
void OutputLineReceived(object source, LineReceivedEventArgs e)
{
TestRunnerCategory.AppendLine(e.Line);
}
void ProcessExited(object source, EventArgs e)
{
WorkbenchSingleton.SafeThreadAsyncCall(TestsFinished);
}
void TestFinished(object source, TestFinishedEventArgs e)
{
WorkbenchSingleton.SafeThreadAsyncCall(ShowResult, e.Result);
}
}
public class RunTestWithDebuggerCommand : AbstractRunTestCommand
{
public override void Run()
{
if (DebuggerService.IsDebuggerLoaded && DebuggerService.CurrentDebugger.IsDebugging) {
if (MessageService.AskQuestion("${res:XML.MainMenu.RunMenu.Compile.StopDebuggingQuestion}",
"${res:XML.MainMenu.RunMenu.Compile.StopDebuggingTitle}"))
{
DebuggerService.CurrentDebugger.Stop();
base.Run();
}
} else {
base.Run();
}
}
protected override void RunTests(UnitTestApplicationStartHelper helper)
{
bool running = false;
try {
TestRunnerCategory.AppendLine(helper.GetCommandLine());
ProcessStartInfo startInfo = new ProcessStartInfo(helper.UnitTestApplication);
startInfo.Arguments = helper.GetArguments();
startInfo.WorkingDirectory = UnitTestApplicationStartHelper.UnitTestApplicationDirectory;
DebuggerService.DebugStopped += DebuggerFinished;
DebuggerService.CurrentDebugger.Start(startInfo);
running = true;
} finally {
if (!running) {
DebuggerService.DebugStopped -= DebuggerFinished;
}
}
}
protected override void OnStop()
{
if (DebuggerService.CurrentDebugger.IsDebugging) {
DebuggerService.CurrentDebugger.Stop();
}
}
void DebuggerFinished(object sender, EventArgs e)
{
DebuggerService.DebugStopped -= DebuggerFinished;
WorkbenchSingleton.SafeThreadAsyncCall(TestsFinished);
}
}
public class RunAllTestsInPadCommand : RunTestInPadCommand
{
public override void Run()
{
// To make sure all tests are run we set the Owner to null.
Owner = null;
base.Run();
}
}
public class RunProjectTestsInPadCommand : RunTestInPadCommand, ITestTreeView
{
public override void Run()
{
Owner = this;
base.Run();
}
public TestMember SelectedMethod {
get { return null; }
}
public TestClass SelectedClass {
get { return null; }
}
public IProject SelectedProject {
get { return ProjectService.CurrentProject; }
}
public string SelectedNamespace {
get { return null; }
}
}
}

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

@ -41,43 +41,25 @@ namespace ICSharpCode.UnitTesting @@ -41,43 +41,25 @@ namespace ICSharpCode.UnitTesting
public class GotoDefinitionCommand : AbstractMenuCommand
{
IFileService fileService;
public GotoDefinitionCommand()
: this(SD.FileService)
{
}
public GotoDefinitionCommand(IFileService fileService)
{
this.fileService = fileService;
}
public override void Run()
{
ITestTreeView treeView = Owner as ITestTreeView;
if (treeView != null) {
var method = treeView.SelectedMethod;
var member = treeView.SelectedMember;
var c = treeView.SelectedClass;
if (method != null) {
GotoMember(method.Resolve());
IEntity entity;
if (member != null) {
entity = member.Resolve();
} else if (c != null) {
GotoClass(c.Resolve());
entity = c.Resolve();
} else {
entity = null;
}
if (entity != null) {
NavigationService.NavigateTo(entity);
}
}
}
void GotoMember(IMember member)
{
if (member != null)
NavigationService.NavigateTo(member);
}
void GotoClass(ITypeDefinition c)
{
if (c != null)
NavigationService.NavigateTo(c);
}
}
public class CollapseAllTestsCommand : AbstractMenuCommand
@ -88,10 +70,9 @@ namespace ICSharpCode.UnitTesting @@ -88,10 +70,9 @@ namespace ICSharpCode.UnitTesting
return;
var treeView = (SharpTreeView)this.Owner;
NRefactory.Utils.TreeTraversal.PreOrder(treeView.Root, n => n.Children).ForEach(n => n.IsExpanded = false);
if (treeView.Root.Children.Count > 0) {
treeView.Root.IsExpanded = true;
if (treeView.Root != null) {
foreach (var n in treeView.Root.Descendants())
n.IsExpanded = false;
}
}
}

72
src/AddIns/Analysis/UnitTesting/Extensions.cs

@ -1,72 +0,0 @@ @@ -1,72 +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.Collections.Specialized;
using System.Linq;
using System.Reflection;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Parser;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.TreeView;
using NUnit.Framework;
namespace ICSharpCode.UnitTesting
{
public static class Extensions
{
public static IEnumerable<TResult> FullOuterJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter,TKey> outerKeySelector, Func<TInner,TKey> innerKeySelector, Func<TOuter,TInner,TResult> resultSelector)
where TInner : class
where TOuter : class
{
var innerLookup = inner.ToLookup(innerKeySelector);
var outerLookup = outer.ToLookup(outerKeySelector);
var innerJoinItems = inner
.Where(innerItem => !outerLookup.Contains(innerKeySelector(innerItem)))
.Select(innerItem => resultSelector(null, innerItem));
return outer
.SelectMany(outerItem => {
var innerItems = innerLookup[outerKeySelector(outerItem)];
return innerItems.Any() ? innerItems : new TInner[] { null };
}, resultSelector)
.Concat(innerJoinItems);
}
public static void OrderedInsert<T>(this IList<T> list, T item, Func<T, T, int> comparer)
{
int index = 0;
while (index < list.Count && comparer(list[index], item) < 0)
index++;
list.Insert(index, item);
}
public static void UpdateTestClasses(this IList<TestClass> testClasses, IRegisteredTestFrameworks testFrameworks, IReadOnlyList<ITypeDefinition> oldTypes, IReadOnlyList<ITypeDefinition> newTypes, TestClass parent, TestProject project)
{
var mappings = oldTypes.FullOuterJoin(newTypes, t => t.ReflectionName, t => t.ReflectionName, Tuple.Create);
foreach (Tuple<ITypeDefinition, ITypeDefinition> mapping in mappings) {
if (mapping.Item2 == null)
testClasses.RemoveWhere(c => c.FullName == mapping.Item1.ReflectionName);
else if (mapping.Item1 == null)
testClasses.Add(new TestClass(project, testFrameworks, mapping.Item2.ReflectionName, mapping.Item2, parent));
else {
var testClass = testClasses.SingleOrDefault(c => c.FullName == mapping.Item1.ReflectionName);
if (testClass == null)
testClasses.Add(new TestClass(project, testFrameworks, mapping.Item2.ReflectionName, mapping.Item2, parent));
else
testClass.UpdateClass(mapping.Item2);
}
}
}
}
}

15
src/AddIns/Analysis/UnitTesting/Gui/UnitTestsPad.cs

@ -6,7 +6,6 @@ using System.Collections.Generic; @@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using ICSharpCode.Core;
using ICSharpCode.Core.Presentation;
using ICSharpCode.NRefactory.TypeSystem;
@ -20,6 +19,7 @@ namespace ICSharpCode.UnitTesting @@ -20,6 +19,7 @@ namespace ICSharpCode.UnitTesting
{
public class UnitTestsPad : AbstractPadContent
{
TestSolution testSolution;
TestTreeView treeView;
bool disposed;
DockPanel panel;
@ -28,13 +28,14 @@ namespace ICSharpCode.UnitTesting @@ -28,13 +28,14 @@ namespace ICSharpCode.UnitTesting
static UnitTestsPad instance;
public UnitTestsPad()
: this(TestService.RegisteredTestFrameworks)
: this(TestService.RegisteredTestFrameworks, TestService.Solution)
{
}
public UnitTestsPad(IRegisteredTestFrameworks testFrameworks)
public UnitTestsPad(IRegisteredTestFrameworks testFrameworks, TestSolution testSolution)
{
instance = this;
this.testSolution = testSolution;
panel = new DockPanel();
@ -42,7 +43,7 @@ namespace ICSharpCode.UnitTesting @@ -42,7 +43,7 @@ namespace ICSharpCode.UnitTesting
panel.Children.Add(toolBar);
DockPanel.SetDock(toolBar, Dock.Top);
treeView = new TestTreeView(testFrameworks);
treeView = new TestTreeView(testFrameworks, testSolution);
panel.Children.Add(treeView);
// Add the load solution projects thread ended handler before
@ -51,8 +52,6 @@ namespace ICSharpCode.UnitTesting @@ -51,8 +52,6 @@ namespace ICSharpCode.UnitTesting
SD.ParserService.LoadSolutionProjectsThread.Finished += LoadSolutionProjectsThreadFinished;
OnAddedLoadSolutionProjectsThreadEndedHandler();
treeView.Root = new RootUnitTestNode();
ProjectService.SolutionClosed += SolutionClosed;
ProjectService.SolutionFolderRemoved += SolutionFolderRemoved;
ProjectService.ProjectAdded += ProjectAdded;
@ -95,7 +94,7 @@ namespace ICSharpCode.UnitTesting @@ -95,7 +94,7 @@ namespace ICSharpCode.UnitTesting
//
public IProject[] GetProjects()
{
return TestService.TestableProjects.Select(tp => tp.Project).ToArray();
return testSolution.TestableProjects.Select(tp => tp.Project).ToArray();
}
// public TestProject GetTestProject(IProject project)
@ -285,7 +284,7 @@ namespace ICSharpCode.UnitTesting @@ -285,7 +284,7 @@ namespace ICSharpCode.UnitTesting
public void ResetTestResults()
{
foreach (var testProject in TestService.TestableProjects)
foreach (var testProject in testSolution.TestableProjects)
testProject.ResetTestResults();
}
}

12
src/AddIns/Analysis/UnitTesting/Implementation/UnitTestFileService.cs

@ -7,18 +7,8 @@ using ICSharpCode.SharpDevelop; @@ -7,18 +7,8 @@ using ICSharpCode.SharpDevelop;
namespace ICSharpCode.UnitTesting
{
public class UnitTestFileService : IUnitTestFileService
public class UnitTestFileService : IFileSystem
{
public void OpenFile(string fileName)
{
FileService.OpenFile(fileName);
}
public void JumpToFilePosition(string fileName, int line, int column)
{
FileService.JumpToFilePosition(fileName, line, column);
}
public bool FileExists(string fileName)
{
return File.Exists(fileName);

7
src/AddIns/Analysis/UnitTesting/Interfaces/IRegisteredTestFrameworks.cs

@ -14,13 +14,10 @@ namespace ICSharpCode.UnitTesting @@ -14,13 +14,10 @@ namespace ICSharpCode.UnitTesting
ITestRunner CreateTestRunner(IProject project);
ITestRunner CreateTestDebugger(IProject project);
bool IsTestMethod(IMethod method, ICompilation compilation);
bool IsTestCase(IMethod method, ICompilation compilation);
bool IsTestClass(ITypeDefinition typeDefinition, ICompilation compilation);
bool IsTestMember(IMember member);
bool IsTestClass(ITypeDefinition typeDefinition);
bool IsTestProject(IProject project);
IEnumerable<IMethod> GetTestMethodsFor(ITypeDefinition typeDefinition, ICompilation compilation);
bool IsBuildNeededBeforeTestRunForProject(IProject project);
}
}

7
src/AddIns/Analysis/UnitTesting/Interfaces/ITestFramework.cs

@ -10,12 +10,11 @@ namespace ICSharpCode.UnitTesting @@ -10,12 +10,11 @@ namespace ICSharpCode.UnitTesting
{
public interface ITestFramework
{
bool IsTestMethod(IMethod method, ICompilation compilation);
bool IsTestCase(IMethod method, ICompilation compilation);
bool IsTestClass(ITypeDefinition testClass, ICompilation compilation);
bool IsTestMember(IMember member);
bool IsTestClass(ITypeDefinition testClass);
bool IsTestProject(IProject project);
IEnumerable<IMethod> GetTestMethodsFor(ITypeDefinition typeDefinition);
IEnumerable<TestMember> GetTestMembersFor(TestProject project, ITypeDefinition typeDefinition);
ITestRunner CreateTestRunner();
ITestRunner CreateTestDebugger();

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

@ -13,7 +13,7 @@ namespace ICSharpCode.UnitTesting @@ -13,7 +13,7 @@ namespace ICSharpCode.UnitTesting
/// <summary>
/// Gets the selected member in the test tree view.
/// </summary>
TestMember SelectedMethod {get;}
TestMember SelectedMember {get;}
/// <summary>
/// Gets the selected class in the test tree view.

13
src/AddIns/Analysis/UnitTesting/Interfaces/IUnitTestFileService.cs

@ -1,13 +0,0 @@ @@ -1,13 +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 IUnitTestFileService : IFileSystem
{
void OpenFile(string fileName);
void JumpToFilePosition(string fileName, int line, int column);
}
}

49
src/AddIns/Analysis/UnitTesting/Model/TestClass.cs

@ -20,19 +20,15 @@ namespace ICSharpCode.UnitTesting @@ -20,19 +20,15 @@ namespace ICSharpCode.UnitTesting
/// </summary>
public class TestClass : ViewModelBase
{
string fullName;
ObservableCollection<IUnresolvedTypeDefinition> parts;
IList<IUnresolvedTypeDefinition> parts;
readonly ObservableCollection<TestMember> testMembers;
readonly ObservableCollection<TestClass> nestedClasses;
IRegisteredTestFrameworks testFrameworks;
public TestClass(TestProject project, IRegisteredTestFrameworks testFrameworks, string fullName, ITypeDefinition definition, TestClass parent = null)
public TestClass(TestProject project, ITypeDefinition definition, TestClass parent = null)
{
this.parts = new ObservableCollection<IUnresolvedTypeDefinition>();
this.testMembers = new ObservableCollection<TestMember>();
this.nestedClasses = new ObservableCollection<TestClass>();
this.testFrameworks = testFrameworks;
this.fullName = fullName;
Project = project;
Parent = parent;
UpdateClass(definition);
@ -43,9 +39,9 @@ namespace ICSharpCode.UnitTesting @@ -43,9 +39,9 @@ namespace ICSharpCode.UnitTesting
public TestProject Project { get; private set; }
/// <summary>
/// Gets the underlying IClass for this test class.
/// Gets the underlying IUnresolvedTypeDefinitions for this test class.
/// </summary>
public IEnumerable<IUnresolvedTypeDefinition> Parts {
public IList<IUnresolvedTypeDefinition> Parts {
get { return parts; }
}
@ -57,29 +53,25 @@ namespace ICSharpCode.UnitTesting @@ -57,29 +53,25 @@ namespace ICSharpCode.UnitTesting
get { return nestedClasses; }
}
public string FullName {
get { return fullName; }
}
/// <summary>
/// Gets the name of the class.
/// </summary>
public string Name {
get { return parts.First().Name; }
get { return parts[0].Name; }
}
/// <summary>
/// Gets the fully qualified name of the class.
/// </summary>
public string QualifiedName {
get { return parts.First().ReflectionName; }
public string ReflectionName {
get { return parts[0].ReflectionName; }
}
/// <summary>
/// Gets the namespace of this class.
/// </summary>
public string Namespace {
get { return parts.First().Namespace; }
get { return parts[0].Namespace; }
}
TestResultType testResult;
@ -113,7 +105,7 @@ namespace ICSharpCode.UnitTesting @@ -113,7 +105,7 @@ namespace ICSharpCode.UnitTesting
/// </summary>
public void UpdateTestResult(TestResult testResult)
{
var member = testMembers.SingleOrDefault(m => m.Method.ReflectionName == testResult.Name);
var member = testMembers.SingleOrDefault(m => m.Member.ReflectionName == testResult.Name);
member.TestResult = testResult.ResultType;
var parent = this;
while (parent != null) {
@ -143,8 +135,17 @@ namespace ICSharpCode.UnitTesting @@ -143,8 +135,17 @@ namespace ICSharpCode.UnitTesting
/// Updates the members and class based on the new class
/// information that has been parsed.
/// </summary>
public void UpdateClass(ITypeDefinition definition)
public void UpdateClass(ITypeDefinition typeDefinition)
{
this.parts = typeDefinition.Parts;
testMembers.Clear();
testMembers.AddRange(Project.TestFramework.GetTestMembersFor(Project, typeDefinition));
/*var oldParts = this.parts;
nestedClasses.UpdateTestClasses(testFrameworks,
int i = 0;
while (i < parts.Count) {
var part = parts[i];
@ -158,11 +159,15 @@ namespace ICSharpCode.UnitTesting @@ -158,11 +159,15 @@ namespace ICSharpCode.UnitTesting
if (!parts.Any(p => p.UnresolvedFile.FileName == part.UnresolvedFile.FileName && p.Region == part.Region))
parts.Add(part);
}
testMembers.RemoveWhere(m => !definition.Methods.Any(dm => dm.ReflectionName == m.Method.ReflectionName && testFrameworks.IsTestMethod(dm, definition.Compilation)));
testMembers.AddRange(definition.Methods.Where(m => testFrameworks.IsTestMethod(m, definition.Compilation) && !testMembers.Any(dm => dm.Method.ReflectionName == m.ReflectionName)).Select(m => new TestMember(Project, (IUnresolvedMethod)m.UnresolvedMember, testFrameworks.IsTestCase(m, definition.Compilation))));
testMembers.RemoveWhere(m => !definition.Methods.Any(dm => dm.ReflectionName == m.Member.ReflectionName && testFrameworks.IsTestMethod(dm)));
testMembers.AddRange(
definition.Methods.Where(m => testFrameworks.IsTestMethod(m, definition.Compilation)
&& !testMembers.Any(dm => dm.Member.ReflectionName == m.ReflectionName))
.Select(m => new TestMember(Project, (IUnresolvedMethod)m.UnresolvedMember, testFrameworks.IsTestCase(m, definition.Compilation))));
var context = new SimpleTypeResolveContext(definition);
nestedClasses.UpdateTestClasses(testFrameworks, nestedClasses.Select(tc => new DefaultResolvedTypeDefinition(context, tc.Parts.ToArray())).ToList(), definition.NestedTypes.Where(nt => testFrameworks.IsTestClass(nt, definition.Compilation)).ToList(), this, Project);
*/
}
/// <summary>
@ -180,12 +185,12 @@ namespace ICSharpCode.UnitTesting @@ -180,12 +185,12 @@ namespace ICSharpCode.UnitTesting
public ITypeDefinition Resolve()
{
ICompilation compilation = SD.ParserService.GetCompilation(Project.Project);
return parts.First().Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)).GetDefinition();
return parts[0].Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)).GetDefinition();
}
public override string ToString()
{
return string.Format("[TestClass TestResult={0}, FullName={1}]", testResult, fullName);
return string.Format("[TestClass TestResult={0}, Name={1}]", testResult, this.ReflectionName);
}
}
}

27
src/AddIns/Analysis/UnitTesting/Model/TestMember.cs

@ -14,28 +14,25 @@ namespace ICSharpCode.UnitTesting @@ -14,28 +14,25 @@ namespace ICSharpCode.UnitTesting
/// </summary>
public class TestMember : ViewModelBase
{
IUnresolvedMethod method;
IUnresolvedMember member;
public IUnresolvedMethod Method {
get { return method; }
public IUnresolvedMember Member {
get { return member; }
}
public TestProject Project { get; private set; }
public bool IsTestCase { get; private set; }
public TestMember(TestProject project, IUnresolvedMethod method, bool isTestCase)
public TestMember(TestProject project, IUnresolvedMember member)
{
if (method == null)
throw new ArgumentNullException("method");
this.method = method;
if (member == null)
throw new ArgumentNullException("member");
this.member = member;
this.Project = project;
this.IsTestCase = isTestCase;
}
TestResultType testResult;
public TestResultType TestResult {
public virtual TestResultType TestResult {
get { return testResult; }
set {
if (testResult < value) {
@ -45,20 +42,20 @@ namespace ICSharpCode.UnitTesting @@ -45,20 +42,20 @@ namespace ICSharpCode.UnitTesting
}
}
public void ResetTestResult()
public virtual void ResetTestResult()
{
testResult = TestResultType.None;
}
public IMethod Resolve()
public IMember Resolve()
{
ICompilation compilation = SD.ParserService.GetCompilation(Project.Project);
return method.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly));
return member.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly));
}
public override string ToString()
{
return string.Format("[TestMember Method={0}, TestResult={1}]", method, testResult);
return string.Format("[TestMember Method={0}, TestResult={1}]", member, testResult);
}
}
}

118
src/AddIns/Analysis/UnitTesting/Model/TestProject.cs

@ -23,33 +23,85 @@ namespace ICSharpCode.UnitTesting @@ -23,33 +23,85 @@ namespace ICSharpCode.UnitTesting
/// </summary>
public class TestProject : ViewModelBase
{
IProject project;
IRegisteredTestFrameworks testFrameworks;
readonly IProject project;
readonly ITestFramework testFramework;
readonly ObservableCollection<TestClass> testClasses;
public TestProject(IProject project)
public TestProject(IProject project, ITestFramework testFramework)
{
this.testFramework = testFramework;
this.project = project;
this.testFrameworks = TestService.RegisteredTestFrameworks;
project.ParseInformationUpdated += project_ParseInformationUpdated;
var compilation = SD.ParserService.GetCompilation(project);
var classes = project.ProjectContent
.Resolve(compilation.TypeResolveContext)
.TopLevelTypeDefinitions
.Where(td => testFrameworks.IsTestClass(td, compilation))
.Select(g => new TestClass(this, testFrameworks, g.ReflectionName, g));
testClasses = new ObservableCollection<TestClass>(classes);
testClasses = new ObservableCollection<TestClass>(
from td in compilation.MainAssembly.TopLevelTypeDefinitions
where testFramework.IsTestClass(td)
select new TestClass(this, td)
);
}
void project_ParseInformationUpdated(object sender, ParseInformationEventArgs e)
HashSet<FullNameAndTypeParameterCount> dirtyTypeDefinitions = new HashSet<FullNameAndTypeParameterCount>();
public void NotifyParseInformationChanged(IUnresolvedFile oldUnresolvedFile, IUnresolvedFile newUnresolvedFile)
{
var context = new SimpleTypeResolveContext(SD.ParserService.GetCompilation(project).MainAssembly);
IEnumerable<ITypeDefinition> @new;
if (e.NewUnresolvedFile != null)
@new = e.NewUnresolvedFile.TopLevelTypeDefinitions.Select(utd => utd.Resolve(context).GetDefinition()).Where(x => x != null && testFrameworks.IsTestClass(x, SD.ParserService.GetCompilation(project)));
else
@new = Enumerable.Empty<ITypeDefinition>();
testClasses.UpdateTestClasses(testFrameworks, testClasses.Where(tc => tc.Parts.Any(td => td.UnresolvedFile.FileName == e.OldUnresolvedFile.FileName)).Select(tc => new DefaultResolvedTypeDefinition(context, tc.Parts.ToArray())).ToList(), @new.ToList(), null, this);
AddToDirtyList(oldUnresolvedFile);
AddToDirtyList(newUnresolvedFile);
ProcessUpdates();
}
void AddToDirtyList(IUnresolvedFile unresolvedFile)
{
if (unresolvedFile != null) {
foreach (var td in unresolvedFile.TopLevelTypeDefinitions) {
dirtyTypeDefinitions.Add(new FullNameAndTypeParameterCount(td.Namespace, td.Name, td.TypeParameters.Count));
}
}
}
void ProcessUpdates()
{
var compilation = SD.ParserService.GetCompilation(project);
var context = new SimpleTypeResolveContext(compilation.MainAssembly);
var testClassNameToIndex = new Dictionary<FullNameAndTypeParameterCount, int>();
for (int i = 0; i < testClasses.Count; i++) {
var primaryPart = testClasses[i].Parts[0];
testClassNameToIndex[new FullNameAndTypeParameterCount(primaryPart.Namespace, primaryPart.Name, primaryPart.TypeParameters.Count)] = i;
}
List<int> testClassesToRemove = new List<int>();
foreach (var dirtyTypeDef in dirtyTypeDefinitions) {
ITypeDefinition typeDef = compilation.MainAssembly.GetTypeDefinition(dirtyTypeDef.Namespace, dirtyTypeDef.Name, dirtyTypeDef.TypeParameterCount);
int pos;
if (testClassNameToIndex.TryGetValue(dirtyTypeDef, out pos)) {
if (typeDef == null) {
// Test class was removed completely (no parts left)
// Removing the class messes up the indices stored in the dictionary,
// so we'll just remember that we need to remove the class
testClassesToRemove.Add(pos);
} else {
// Test class was modified
// Check if it's still a test class:
if (testFramework.IsTestClass(typeDef))
testClasses[pos].UpdateClass(typeDef);
else
testClassesToRemove.Add(pos);
}
} else if (typeDef != null && testFramework.IsTestClass(typeDef)) {
// Test class was added
testClasses.Add(new TestClass(this, typeDef));
}
}
dirtyTypeDefinitions.Clear();
// Now remove the outdated test classes
testClassesToRemove.Sort();
foreach (int index in testClassesToRemove) {
testClasses.RemoveAt(index);
}
}
public ITestFramework TestFramework {
get { return testFramework; }
}
public IProject Project {
@ -60,23 +112,39 @@ namespace ICSharpCode.UnitTesting @@ -60,23 +112,39 @@ namespace ICSharpCode.UnitTesting
get { return testClasses; }
}
public TestMember GetTestMethod(string fullName)
public TestMember GetTestMember(IMember member)
{
if (member != null)
return GetTestMember(member.ReflectionName);
else
return null;
}
public TestMember GetTestMember(string reflectionName)
{
foreach (var tc in testClasses) {
var result = TreeTraversal.PostOrder(tc, c => c.NestedClasses)
.SelectMany(c => c.Members)
.SingleOrDefault(m => fullName.Equals(m.Method.ReflectionName, StringComparison.Ordinal));
.SingleOrDefault(m => reflectionName.Equals(m.Member.ReflectionName, StringComparison.Ordinal));
if (result != null)
return result;
}
return null;
}
public TestClass FindTestClass(string fullName)
public TestClass GetTestClass(ITypeDefinition typeDefinition)
{
if (typeDefinition != null)
return GetTestClass(typeDefinition.ReflectionName);
else
return null;
}
public TestClass GetTestClass(string reflectionName)
{
foreach (var tc in testClasses) {
foreach (var c in TreeTraversal.PostOrder(tc, c => c.NestedClasses)) {
var method = c.Members.SingleOrDefault(m => fullName.Equals(m.Method.ReflectionName, StringComparison.Ordinal));
var method = c.Members.SingleOrDefault(m => reflectionName.Equals(m.Member.ReflectionName, StringComparison.Ordinal));
if (method != null)
return c;
}
@ -86,7 +154,7 @@ namespace ICSharpCode.UnitTesting @@ -86,7 +154,7 @@ namespace ICSharpCode.UnitTesting
public void UpdateTestResult(TestResult result)
{
TestClass testClass = FindTestClass(result.Name);
TestClass testClass = GetTestClass(result.Name);
if (testClass != null) {
testClass.UpdateTestResult(result);
TestResult = GetTestResult(testClasses);

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

@ -0,0 +1,157 @@ @@ -0,0 +1,157 @@
// 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.Linq;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Parser;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// Manages the collection of TestProjects.
/// </summary>
public class TestSolution
{
readonly IRegisteredTestFrameworks registeredTestFrameworks;
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)
{
if (registeredTestFrameworks == null)
throw new ArgumentNullException("registeredTestFrameworks");
this.registeredTestFrameworks = registeredTestFrameworks;
ProjectService.SolutionLoaded += ProjectService_SolutionLoaded;
ProjectService.SolutionClosed += ProjectService_SolutionClosed;
ProjectService.ProjectAdded += ProjectService_ProjectAdded;
ProjectService.ProjectRemoved += ProjectService_ProjectRemoved;
SD.ParserService.LoadSolutionProjectsThread.Finished += SD_ParserService_LoadSolutionProjectsThread_Finished;
if (ProjectService.OpenSolution != null) {
ProjectService_SolutionLoaded(null, new SolutionEventArgs(ProjectService.OpenSolution));
SD_ParserService_LoadSolutionProjectsThread_Finished(null, null);
}
}
/// <summary>
/// Retrieves the TestProject for the specified project.
/// </summary>
public TestProject GetTestProject(IProject currentProject)
{
return testableProjects.FirstOrDefault(p => p.Project == currentProject);
}
/// <summary>
/// Creates a TestProject for an IProject.
/// This class takes care of changes in the test framework and will recreate the testProject
/// if the test framework changes.
/// </summary>
class ProjectChangeListener
{
readonly TestSolution testSolution;
internal readonly IProject project;
TestProject testProject;
public ProjectChangeListener(TestSolution testSolution, IProject project)
{
this.testSolution = testSolution;
this.project = project;
}
public void Start()
{
project.ParseInformationUpdated += project_ParseInformationUpdated;
CheckTestFramework();
}
public void Stop()
{
project.ParseInformationUpdated -= project_ParseInformationUpdated;
// Remove old testProject
if (testProject != null) {
testSolution.testableProjects.Remove(testProject);
testProject = null;
}
}
void project_ParseInformationUpdated(object sender, ParseInformationEventArgs e)
{
if (testProject != null) {
testProject.NotifyParseInformationChanged(e.OldUnresolvedFile, e.NewUnresolvedFile);
}
}
internal void CheckTestFramework()
{
ITestFramework newTestFramework = testSolution.registeredTestFrameworks.GetTestFrameworkForProject(project);
if (newTestFramework != null && testProject != null && testProject.TestFramework == newTestFramework)
return; // test framework is unchanged
// Remove old testProject
if (testProject != null) {
testSolution.testableProjects.Remove(testProject);
testProject = null;
}
// Create new testProject
if (newTestFramework != null) {
testProject = new TestProject(project, newTestFramework);
testSolution.testableProjects.Add(testProject);
}
}
}
void ProjectService_ProjectAdded(object sender, ProjectEventArgs e)
{
AddProject(e.Project);
}
void AddProject(IProject project)
{
ProjectChangeListener listener = new ProjectChangeListener(this, project);
changeListeners.Add(listener);
listener.Start();
}
void ProjectService_ProjectRemoved(object sender, ProjectEventArgs e)
{
for (int i = 0; i < changeListeners.Count; i++) {
if (changeListeners[i].project == e.Project) {
changeListeners[i].Stop();
changeListeners.RemoveAt(i);
break;
}
}
}
void ProjectService_SolutionClosed(object sender, EventArgs e)
{
for (int i = 0; i < changeListeners.Count; i++) {
changeListeners[i].Stop();
}
changeListeners.Clear();
}
void ProjectService_SolutionLoaded(object sender, SolutionEventArgs e)
{
ProjectService_SolutionClosed(sender, e);
foreach (var project in e.Solution.Projects) {
AddProject(project);
}
}
void SD_ParserService_LoadSolutionProjectsThread_Finished(object sender, EventArgs e)
{
for (int i = 0; i < changeListeners.Count; i++) {
changeListeners[i].CheckTestFramework();
}
}
}
}

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

@ -36,9 +36,9 @@ namespace ICSharpCode.UnitTesting @@ -36,9 +36,9 @@ namespace ICSharpCode.UnitTesting
NamespaceFilter = selectedTests.NamespaceFilter;
}
if (selectedTests.Class != null) {
Fixture = selectedTests.Class.FullName;
Fixture = selectedTests.Class.ReflectionName;
if (selectedTests.Method != null) {
Test = selectedTests.Method.Method.Name;
Test = selectedTests.Method.Member.Name;
}
}
}

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

@ -45,36 +45,33 @@ namespace ICSharpCode.UnitTesting @@ -45,36 +45,33 @@ namespace ICSharpCode.UnitTesting
return testAttribute.Resolve(SD.ParserService.GetCompilation(project).TypeResolveContext).Kind != TypeKind.Unknown;
}
public bool IsTestMethod(IMethod method, ICompilation compilation)
public bool IsTestMember(IMember member)
{
if (method == null)
throw new ArgumentNullException("method");
var testAttribute = NUnitTestFramework.testAttribute.Resolve(compilation.TypeResolveContext);
return IsTestCase(method, compilation) || method.Attributes.Any(a => a.AttributeType.Equals(testAttribute));
}
public bool IsTestCase(IMethod method, ICompilation compilation)
{
if (method == null)
throw new ArgumentNullException("method");
var testCaseAttribute = NUnitTestFramework.testCaseAttribute.Resolve(compilation.TypeResolveContext);
return method.Attributes.Any(a => a.AttributeType.Equals(testCaseAttribute));
if (member == null)
throw new ArgumentNullException("member");
if (member.EntityType != EntityType.Method)
return false;
var testAttribute = NUnitTestFramework.testAttribute.Resolve(member.Compilation);
var testCaseAttribute = NUnitTestFramework.testCaseAttribute.Resolve(member.Compilation);
foreach (var attr in member.Attributes) {
if (attr.AttributeType.Equals(testAttribute) || attr.AttributeType.Equals(testCaseAttribute))
return true;
}
return false;
}
public bool IsTestClass(ITypeDefinition type, ICompilation compilation)
public bool IsTestClass(ITypeDefinition type)
{
if (type == null)
throw new ArgumentNullException("type");
if (type.IsAbstract)
return false;
var testAttribute = NUnitTestFramework.testAttribute.Resolve(compilation.TypeResolveContext);
var testCaseAttribute = NUnitTestFramework.testCaseAttribute.Resolve(compilation.TypeResolveContext);
return type.Methods.Any(m => m.Attributes.Any(a => a.AttributeType.Equals(testAttribute) || a.AttributeType.Equals(testCaseAttribute)));
return type.Methods.Any(IsTestMember);
}
public IEnumerable<IMethod> GetTestMethodsFor(ITypeDefinition typeDefinition)
public IEnumerable<TestMember> GetTestMembersFor(TestProject project, ITypeDefinition typeDefinition)
{
throw new NotImplementedException();
return typeDefinition.Methods.Where(IsTestMember).Select(m => new TestMember(project, m.UnresolvedMember));
}
}
}

10
src/AddIns/Analysis/UnitTesting/Nodes/ClassUnitTestNode.cs

@ -5,6 +5,8 @@ using System; @@ -5,6 +5,8 @@ using System;
using System.Collections.Specialized;
using System.ComponentModel;
using ICSharpCode.SharpDevelop;
namespace ICSharpCode.UnitTesting
{
/// <summary>
@ -43,12 +45,12 @@ namespace ICSharpCode.UnitTesting @@ -43,12 +45,12 @@ namespace ICSharpCode.UnitTesting
switch (e.Action) {
case NotifyCollectionChangedAction.Add:
foreach (TestClass c in e.NewItems) {
Children.OrderedInsert(new ClassUnitTestNode(c), (a, b) => string.CompareOrdinal(a.Text.ToString(), b.Text.ToString()));
Children.OrderedInsert(new ClassUnitTestNode(c), NodeTextComparer);
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (TestClass c in e.OldItems) {
Children.RemoveAll(n => n is ClassUnitTestNode && ((ClassUnitTestNode)n).TestClass.FullName == c.FullName);
Children.RemoveAll(n => n is ClassUnitTestNode && ((ClassUnitTestNode)n).TestClass == c);
}
break;
case NotifyCollectionChangedAction.Reset:
@ -62,12 +64,12 @@ namespace ICSharpCode.UnitTesting @@ -62,12 +64,12 @@ namespace ICSharpCode.UnitTesting
switch (e.Action) {
case NotifyCollectionChangedAction.Add:
foreach (TestMember m in e.NewItems) {
Children.OrderedInsert(new MemberUnitTestNode(m), (a, b) => string.CompareOrdinal(a.Text.ToString(), b.Text.ToString()));
Children.OrderedInsert(new MemberUnitTestNode(m), NodeTextComparer);
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (TestMember m in e.OldItems) {
Children.RemoveAll(n => n is MemberUnitTestNode && ((MemberUnitTestNode)n).TestMember.Method.ReflectionName == m.Method.ReflectionName);
Children.RemoveAll(n => n is MemberUnitTestNode && ((MemberUnitTestNode)n).TestMember.Member.ReflectionName == m.Member.ReflectionName);
}
break;
case NotifyCollectionChangedAction.Reset:

4
src/AddIns/Analysis/UnitTesting/Nodes/MemberUnitTestNode.cs

@ -34,12 +34,12 @@ namespace ICSharpCode.UnitTesting @@ -34,12 +34,12 @@ namespace ICSharpCode.UnitTesting
}
public override object Text {
get { return testMember.Method.Name; }
get { return testMember.Member.Name; }
}
public override void ActivateItem(System.Windows.RoutedEventArgs e)
{
var region = testMember.Method.Region;
var region = testMember.Member.Region;
SD.FileService.JumpToFilePosition(new FileName(region.FileName), region.BeginLine, region.BeginColumn);
}
}

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

@ -49,14 +49,14 @@ namespace ICSharpCode.UnitTesting @@ -49,14 +49,14 @@ namespace ICSharpCode.UnitTesting
if (c.Namespace == "<invalid>") continue;
string namespaceSuffix = GetNamespaceSuffix(c.Namespace, project.Project.RootNamespace);
if (string.IsNullOrEmpty(namespaceSuffix)) {
Children.OrderedInsert(new ClassUnitTestNode(c), (a, b) => string.CompareOrdinal(a.Text.ToString(), b.Text.ToString()));
Children.OrderedInsert(new ClassUnitTestNode(c), NodeTextComparer);
} else {
var node = FindNamespace(namespaceSuffix);
if (node == null) {
node = new NamespaceUnitTestNode(namespaceSuffix);
Children.OrderedInsert(node, (a, b) => string.CompareOrdinal(a.Text.ToString(), b.Text.ToString()));
Children.OrderedInsert(node, NodeTextComparer);
}
node.Children.OrderedInsert(new ClassUnitTestNode(c), (a, b) => string.CompareOrdinal(a.Text.ToString(), b.Text.ToString()));
node.Children.OrderedInsert(new ClassUnitTestNode(c), NodeTextComparer);
}
}
break;
@ -65,11 +65,11 @@ namespace ICSharpCode.UnitTesting @@ -65,11 +65,11 @@ namespace ICSharpCode.UnitTesting
if (c.Namespace == "<invalid>") continue;
string namespaceSuffix = GetNamespaceSuffix(c.Namespace, project.Project.RootNamespace);
if (string.IsNullOrEmpty(namespaceSuffix)) {
Children.RemoveWhere(n => n is ClassUnitTestNode && ((ClassUnitTestNode)n).TestClass.FullName == c.FullName);
Children.RemoveAll(n => n is ClassUnitTestNode && ((ClassUnitTestNode)n).TestClass == c);
} else {
UnitTestBaseNode node = FindNamespace(namespaceSuffix);
if (node == null) continue;
node.Children.RemoveWhere(n => n is ClassUnitTestNode && ((ClassUnitTestNode)n).TestClass.FullName == c.FullName);
node.Children.RemoveAll(n => n is ClassUnitTestNode && ((ClassUnitTestNode)n).TestClass == c);
while (node.Children.Count == 0) {
var parent = (UnitTestBaseNode)node.Parent;
if (parent == null) break;

13
src/AddIns/Analysis/UnitTesting/Nodes/RootUnitTestNode.cs

@ -26,20 +26,23 @@ namespace ICSharpCode.UnitTesting @@ -26,20 +26,23 @@ namespace ICSharpCode.UnitTesting
/// </summary>
public class RootUnitTestNode : UnitTestBaseNode
{
public RootUnitTestNode()
readonly TestSolution testSolution;
public RootUnitTestNode(TestSolution testSolution)
{
TestService.TestableProjects.CollectionChanged += TestService_TestableProjects_CollectionChanged;
this.testSolution = testSolution;
testSolution.TestableProjects.CollectionChanged += TestSolution_TestableProjects_CollectionChanged;
LazyLoading = true;
}
void TestService_TestableProjects_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
void TestSolution_TestableProjects_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action) {
case NotifyCollectionChangedAction.Add:
Children.AddRange(e.NewItems.OfType<TestProject>().Select(p => new ProjectUnitTestNode(p)));
break;
case NotifyCollectionChangedAction.Remove:
Children.RemoveWhere(node => node is ProjectUnitTestNode && e.OldItems.OfType<TestProject>().Any(p => p.Project == ((ProjectUnitTestNode)node).Project));
Children.RemoveAll(node => node is ProjectUnitTestNode && e.OldItems.OfType<TestProject>().Any(p => p.Project == ((ProjectUnitTestNode)node).Project));
break;
case NotifyCollectionChangedAction.Reset:
LoadChildren();
@ -50,7 +53,7 @@ namespace ICSharpCode.UnitTesting @@ -50,7 +53,7 @@ namespace ICSharpCode.UnitTesting
protected override void LoadChildren()
{
Children.Clear();
Children.AddRange(TestService.TestableProjects.Select(p => new ProjectUnitTestNode(p)));
Children.AddRange(testSolution.TestableProjects.Select(p => new ProjectUnitTestNode(p)));
}
public override object Text {

4
src/AddIns/Analysis/UnitTesting/Nodes/UnitTestBaseNode.cs

@ -2,13 +2,17 @@ @@ -2,13 +2,17 @@
// 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 {

50
src/AddIns/Analysis/UnitTesting/Service/RegisteredTestFrameworks.cs

@ -7,6 +7,7 @@ using System.Linq; @@ -7,6 +7,7 @@ using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
@ -33,59 +34,28 @@ namespace ICSharpCode.UnitTesting @@ -33,59 +34,28 @@ namespace ICSharpCode.UnitTesting
return null;
}
public bool IsTestMethod(IMethod method, ICompilation compilation)
public bool IsTestMember(IMember member)
{
ITestFramework testFramework = GetTestFramework(method, compilation);
ITestFramework testFramework = GetTestFramework(member);
if (testFramework != null) {
return testFramework.IsTestMethod(method, compilation);
return testFramework.IsTestMember(member);
}
return false;
}
public bool IsTestCase(IMethod method, ICompilation compilation)
ITestFramework GetTestFramework(IEntity entity)
{
ITestFramework testFramework = GetTestFramework(method, compilation);
if (testFramework != null) {
return testFramework.IsTestCase(method, compilation);
}
return false;
}
public IEnumerable<IMethod> GetTestMethodsFor(ITypeDefinition type, ICompilation compilation)
{
ITestFramework testFramework = GetTestFramework(type, compilation);
if (testFramework != null)
return testFramework.GetTestMethodsFor(type);
return new IMethod[0];
}
ITestFramework GetTestFramework(IMethod method, ICompilation compilation)
{
if (method != null) {
return GetTestFramework(method.DeclaringTypeDefinition, compilation);
}
return null;
}
ITestFramework GetTestFramework(ITypeDefinition c, ICompilation compilation)
{
IProject project = GetProject(c);
return GetTestFrameworkForProject(project);
}
IProject GetProject(ITypeDefinition c)
{
if (c != null && ProjectService.OpenSolution != null) {
return ProjectService.OpenSolution.FindProjectContainingFile(c.Parts[0].UnresolvedFile.FileName);
if (entity != null) {
return GetTestFrameworkForProject(entity.ParentAssembly.GetProject());
}
return null;
}
public bool IsTestClass(ITypeDefinition c, ICompilation compilation)
public bool IsTestClass(ITypeDefinition c)
{
ITestFramework testFramework = GetTestFramework(c, compilation);
ITestFramework testFramework = GetTestFramework(c);
if (testFramework != null) {
return testFramework.IsTestClass(c, compilation);
return testFramework.IsTestClass(c);
}
return false;
}

31
src/AddIns/Analysis/UnitTesting/Service/SelectedTests.cs

@ -33,26 +33,21 @@ namespace ICSharpCode.UnitTesting @@ -33,26 +33,21 @@ namespace ICSharpCode.UnitTesting
public SelectedTests(object owner, IProject[] selectedProjects)
{
// IProject project = TestableCondition.GetProject(owner);
// if (project != null) {
// projects.Add(project);
// } else {
// projects.AddRange(selectedProjects);
// }
//
// member = TestableCondition.GetMember(owner);
// c = GetClass(member, owner);
// namespaceFilter = TestableCondition.GetNamespace(owner);
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);
}
// static TestClass GetClass(IMember member, Object owner)
// {
// if (member != null) {
// return member.DeclaringType;
// }
// return TestableCondition.GetClass(owner);
// }
public bool HasProjects {
get { return projects.Count > 0; }
}

82
src/AddIns/Analysis/UnitTesting/Service/TestService.cs

@ -2,13 +2,8 @@ @@ -2,13 +2,8 @@
// 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.Linq;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
@ -48,76 +43,15 @@ namespace ICSharpCode.UnitTesting @@ -48,76 +43,15 @@ namespace ICSharpCode.UnitTesting
"${res:ICSharpCode.NUnitPad.NUnitPadContent.PadName}");
}
static readonly ObservableCollection<TestProject> testableProjects = new ObservableCollection<TestProject>();
public static ObservableCollection<TestProject> TestableProjects {
get { return testableProjects; }
}
static TestService()
{
ProjectService.SolutionCreated += ProjectService_SolutionCreated;
ProjectService.SolutionLoaded += ProjectService_SolutionLoaded;
ProjectService.SolutionClosed += ProjectService_SolutionClosed;
ProjectService.ProjectCreated += ProjectService_ProjectCreated;
ProjectService.ProjectAdded += ProjectService_ProjectAdded;
ProjectService.ProjectRemoved += ProjectService_ProjectRemoved;
SD.ParserService.LoadSolutionProjectsThread.Finished += SD_ParserService_LoadSolutionProjectsThread_Finished;
// TODO: get rid of static service.
// We don't even know for sure that we're on the main thread when the cctor runs
SD_ParserService_LoadSolutionProjectsThread_Finished(null, null);
}
static void SD_ParserService_LoadSolutionProjectsThread_Finished(object sender, EventArgs e)
{
testableProjects.Clear();
testableProjects.AddRange(GetTestableProjects());
}
static TestSolution solution;
static void ProjectService_ProjectCreated(object sender, ProjectEventArgs e)
{
if (RegisteredTestFrameworks.IsTestProject(e.Project))
testableProjects.Add(new TestProject(e.Project));
}
static void ProjectService_ProjectAdded(object sender, ProjectEventArgs e)
{
if (RegisteredTestFrameworks.IsTestProject(e.Project))
testableProjects.Add(new TestProject(e.Project));
}
static void ProjectService_ProjectRemoved(object sender, ProjectEventArgs e)
{
testableProjects.RemoveWhere(test => test.Project == e.Project);
}
static void ProjectService_SolutionCreated(object sender, SolutionEventArgs e)
{
testableProjects.Clear();
testableProjects.AddRange(GetTestableProjects());
}
static void ProjectService_SolutionClosed(object sender, EventArgs e)
{
testableProjects.Clear();
}
static void ProjectService_SolutionLoaded(object sender, SolutionEventArgs e)
{
testableProjects.Clear();
testableProjects.AddRange(GetTestableProjects());
}
static IEnumerable<TestProject> GetTestableProjects()
{
if (ProjectService.OpenSolution == null)
return Enumerable.Empty<TestProject>();
return ProjectService.OpenSolution.Projects.Where(p => RegisteredTestFrameworks.IsTestProject(p)).Select(p => new TestProject(p));
}
public static TestProject GetTestProject(IProject currentProject)
{
return testableProjects.FirstOrDefault(p => p.Project == currentProject);
public static TestSolution Solution {
get {
SD.MainThread.VerifyAccess();
if (solution == null)
solution = new TestSolution(RegisteredTestFrameworks);
return solution;
}
}
}
}

20
src/AddIns/Analysis/UnitTesting/Service/TestableCondition.cs

@ -29,14 +29,14 @@ namespace ICSharpCode.UnitTesting @@ -29,14 +29,14 @@ namespace ICSharpCode.UnitTesting
{
}
public static IMethod GetMethod(object caller)
public static IMember GetMember(object caller)
{
ITestTreeView testTreeView = caller as ITestTreeView;
if (testTreeView != null && testTreeView.SelectedMethod != null) {
return testTreeView.SelectedMethod.Resolve();
if (testTreeView != null && testTreeView.SelectedMember != null) {
return testTreeView.SelectedMember.Resolve();
}
IEntity entity = ResolveResultMenuCommand.GetEntity(caller);
return entity as IMethod;
return entity as IMember;
}
public static ITypeDefinition GetClass(object caller)
@ -59,11 +59,11 @@ namespace ICSharpCode.UnitTesting @@ -59,11 +59,11 @@ namespace ICSharpCode.UnitTesting
return GetProject(c);
}
static ITypeDefinition GetClassFromMemberOrCaller(object caller)
public static ITypeDefinition GetClassFromMemberOrCaller(object caller)
{
IMethod m = GetMethod(caller);
IMember m = GetMember(caller);
if (m != null) {
return m.DeclaringType.GetDefinition();
return m.DeclaringTypeDefinition;
}
return GetClass(caller);
}
@ -87,13 +87,13 @@ namespace ICSharpCode.UnitTesting @@ -87,13 +87,13 @@ namespace ICSharpCode.UnitTesting
public bool IsValid(object caller, Condition condition)
{
IMethod m = GetMethod(caller);
IMember m = GetMember(caller);
if (m != null) {
return testFrameworks.IsTestMethod(m, m.Compilation);
return testFrameworks.IsTestMember(m);
}
ITypeDefinition c = GetClass(caller);
if (ClassHasProject(c)) {
return testFrameworks.IsTestClass(c, c.Compilation);
return testFrameworks.IsTestClass(c);
}
return false;
}

102
src/AddIns/Analysis/UnitTesting/Src/AllTestsTreeNode.cs

@ -1,102 +0,0 @@ @@ -1,102 +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
{
/// <summary>
/// All Tests root tree node that is added to the test tree when the
/// solution has multiple test projects.
/// </summary>
public class AllTestsTreeNode : TestTreeNode
{
public AllTestsTreeNode()
: base(null, StringParser.Parse("${res:ICSharpCode.UnitTesting.AllTestsTreeNode.Text}"))
{
}
/// <summary>
/// Raised when the all tests tree node is disposed.
/// </summary>
public event EventHandler Disposed;
/// <summary>
/// Disposes this tree node.
/// </summary>
public override void Dispose()
{
base.Dispose();
if (Disposed != null) {
Disposed(this, new EventArgs());
}
}
/// <summary>
/// Adds a new project node as a child of the All Tests node.
/// </summary>
public void AddProjectNode(TestProjectTreeNode node)
{
node.AddTo(this);
node.ImageIndexChanged += TestProjectTreeNodeImageIndexChanged;
}
/// <summary>
/// Removes the project node.
/// </summary>
public void RemoveProjectNode(TestProjectTreeNode node)
{
if (Nodes.Contains(node)) {
node.ImageIndexChanged -= TestProjectTreeNodeImageIndexChanged;
node.Remove();
}
}
void TestProjectTreeNodeImageIndexChanged(object source, EventArgs e)
{
UpdateImageListIndex();
}
/// <summary>
/// Sets the All Tests image index based on the current image
/// indexes of the child project tree nodes.
/// </summary>
void UpdateImageListIndex()
{
int ignored = 0;
int failed = 0;
int passed = 0;
int notRun = 0;
int total = Nodes.Count;
foreach (TestProjectTreeNode projectNode in Nodes) {
switch (projectNode.ImageIndex) {
case (int)TestTreeViewImageListIndex.TestFailed:
failed++;
break;
case (int)TestTreeViewImageListIndex.TestPassed:
passed++;
break;
case (int)TestTreeViewImageListIndex.TestIgnored:
ignored++;
break;
default: // Not run.
notRun++;
break;
}
}
// Update the image index based on the test project results.
if (failed > 0) {
UpdateImageListIndex(TestResultType.Failure);
} else if (ignored > 0) {
UpdateImageListIndex(TestResultType.Ignored);
} else if (passed > 0 && notRun == 0) {
UpdateImageListIndex(TestResultType.Success);
} else {
UpdateImageListIndex(TestResultType.None);
}
}
}
}

53
src/AddIns/Analysis/UnitTesting/Src/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()
{
}
}
}

23
src/AddIns/Analysis/UnitTesting/Src/MessageReceivedEventArgs.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;
namespace ICSharpCode.UnitTesting
{
public delegate void MessageReceivedEventHandler(object sender, MessageReceivedEventArgs e);
public class MessageReceivedEventArgs : EventArgs
{
string message;
public MessageReceivedEventArgs(string message)
{
this.message = message;
}
public string Message {
get { return message; }
}
}
}

47
src/AddIns/Analysis/UnitTesting/Src/MultipleProjectBuildable.cs

@ -1,47 +0,0 @@ @@ -1,47 +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.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// IBuildable implementation that builds several projects.
/// </summary>
public class MultipleProjectBuildable : IBuildable
{
readonly IBuildable[] projects;
public MultipleProjectBuildable(IEnumerable<IBuildable> projects)
{
this.projects = projects.ToArray();
}
public string Name {
get { return string.Empty; }
}
public Solution ParentSolution {
get { return projects.Length > 0 ? projects[0].ParentSolution : null; }
}
public ICollection<IBuildable> GetBuildDependencies(ProjectBuildOptions buildOptions)
{
return projects;
}
public void StartBuild(ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink)
{
// SharpDevelop already has built our dependencies, so we're done immediately.
feedbackSink.Done(true);
}
public ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable)
{
return null;
}
}
}

26
src/AddIns/Analysis/UnitTesting/Src/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();
}
}
}

546
src/AddIns/Analysis/UnitTesting/Src/RunTestCommands.cs

@ -1,546 +0,0 @@ @@ -1,546 +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.Diagnostics;
using System.IO;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Commands;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Project.Commands;
using ICSharpCode.SharpDevelop.Util;
namespace ICSharpCode.UnitTesting
{
public abstract class AbstractRunTestCommand : AbstractMenuCommand
{
static MessageViewCategory testRunnerCategory;
static AbstractRunTestCommand runningTestCommand;
List<IProject> projects;
IProject currentProject;
TestResultsMonitor testResultsMonitor;
public AbstractRunTestCommand()
{
testResultsMonitor = new TestResultsMonitor();
testResultsMonitor.TestFinished += TestFinished;
}
/// <summary>
/// Gets the running test command.
/// </summary>
public static AbstractRunTestCommand RunningTestCommand {
get {
return runningTestCommand;
}
}
/// <summary>
/// Gets whether a test is currently running.
/// </summary>
public static bool IsRunningTest {
get {
return runningTestCommand != null;
}
}
public override void Run()
{
projects = new List<IProject>();
IMember m = TestableCondition.GetMember(Owner);
IClass c = (m != null) ? m.DeclaringType : TestableCondition.GetClass(Owner);
IProject project = TestableCondition.GetProject(Owner);
string namespaceFilter = TestableCondition.GetNamespace(Owner);
if (project != null) {
projects.Add(project);
} else if (UnitTestsPad.Instance != null) {
projects.AddRange(UnitTestsPad.Instance.TestTreeView.GetProjects());
}
if (projects.Count > 0) {
runningTestCommand = this;
try {
BeforeRun();
if (IsRunningTest) {
currentProject = projects[0];
Run(currentProject, namespaceFilter, c, m);
}
} catch {
runningTestCommand = null;
throw;
}
}
}
public static MessageViewCategory TestRunnerCategory {
get {
if (testRunnerCategory == null) {
MessageViewCategory.Create(ref testRunnerCategory, "UnitTesting", "${res:ICSharpCode.NUnitPad.NUnitPadContent.PadName}");
}
return testRunnerCategory;
}
}
/// <summary>
/// Stops running the tests.
/// </summary>
public void Stop()
{
runningTestCommand = null;
UpdateUnitTestsPadToolbar();
projects.Clear();
testResultsMonitor.Stop();
StopMonitoring();
OnStop();
}
/// <summary>
/// Called before all tests are run. If multiple projects are
/// to be tested this is called only once.
/// </summary>
protected virtual void OnBeforeRunTests()
{
}
/// <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()
{
}
protected abstract void RunTests(UnitTestApplicationStartHelper helper);
/// <summary>
/// Called by derived classes when a single test run
/// is finished.
/// </summary>
protected void TestsFinished()
{
WorkbenchSingleton.AssertMainThread();
// Read the rest of the file just in case.
testResultsMonitor.Stop();
testResultsMonitor.Read();
StopMonitoring();
projects.Remove(currentProject);
if (projects.Count > 0) {
currentProject = projects[0];
Run(currentProject, null, null, null);
} else {
runningTestCommand = null;
UpdateUnitTestsPadToolbar();
if (TaskService.SomethingWentWrong && ErrorListPad.ShowAfterBuild) {
ShowErrorList();
}
OnAfterRunTests();
}
}
/// <summary>
/// Called by derived classes to show a single test result.
/// </summary>
protected void ShowResult(TestResult result)
{
if (result.IsFailure || result.IsIgnored) {
TaskService.Add(CreateTask(result));
}
UpdateTestResult(result);
}
/// <summary>
/// Called when the test run should be stopped.
/// </summary>
protected virtual void OnStop()
{
}
/// <summary>
/// Brings the specified pad to the front.
/// </summary>
protected void ShowPad(PadDescriptor padDescriptor)
{
if (padDescriptor != null) {
WorkbenchSingleton.SafeThreadAsyncCall(padDescriptor.BringPadToFront);
}
}
/// <summary>
/// Runs the tests after building the project under test.
/// </summary>
void Run(IProject project, string namespaceFilter, IClass fixture, IMember test)
{
BuildProjectBeforeTestRun build = new BuildProjectBeforeTestRun(project);
build.BuildComplete += delegate {
OnBuildComplete(build.LastBuildResults, project, namespaceFilter, fixture, test);
};
build.Run();
}
void ShowUnitTestsPad()
{
ShowPad(WorkbenchSingleton.Workbench.GetPad(typeof(UnitTestsPad)));
}
void UpdateUnitTestsPadToolbar()
{
if (UnitTestsPad.Instance != null) {
UnitTestsPad.Instance.UpdateToolbar();
}
}
/// <summary>
/// Sets the initial workbench state before starting
/// a test run.
/// </summary>
void BeforeRun()
{
TaskService.BuildMessageViewCategory.ClearText();
TaskService.InUpdate = true;
TaskService.ClearExceptCommentTasks();
TaskService.InUpdate = false;
TestRunnerCategory.ClearText();
ShowUnitTestsPad();
ShowOutputPad();
UpdateUnitTestsPadToolbar();
ResetAllTestResults();
OnBeforeRunTests();
}
/// <summary>
/// Brings output pad to the front.
/// </summary>
void ShowOutputPad()
{
ShowPad(WorkbenchSingleton.Workbench.GetPad(typeof(CompilerMessageView)));
}
Task CreateTask(TestResult result)
{
TaskType taskType = TaskType.Warning;
FileLineReference lineRef = null;
string message = String.Empty;
if (result.IsFailure) {
taskType = TaskType.Error;
lineRef = OutputTextLineParser.GetNUnitOutputFileLineReference(result.StackTrace, true);
message = GetTestResultMessage(result, "${res:NUnitPad.NUnitPadContent.TestTreeView.TestFailedMessage}");
} else if (result.IsIgnored) {
message = GetTestResultMessage(result, "${res:NUnitPad.NUnitPadContent.TestTreeView.TestNotExecutedMessage}");
}
if (lineRef == null) {
lineRef = FindTest(result.Name);
}
if (lineRef != null) {
return new Task(FileName.Create(lineRef.FileName),
message, lineRef.Column, lineRef.Line, taskType);
}
return new Task(null, message, 0, 0, taskType);
}
/// <summary>
/// Returns the test result message if there is on otherwise
/// uses the string resource to create a message.
/// </summary>
string GetTestResultMessage(TestResult result, string stringResource)
{
if (result.Message.Length > 0) {
return result.Message;
}
return StringParser.Parse(stringResource, new string[,] {{"TestCase", result.Name}});
}
/// <summary>
/// Returns the location of the specified test method in the
/// project being tested.
/// </summary>
FileLineReference FindTest(string methodName)
{
TestProject testProject = GetTestProject(currentProject);
if (testProject != null) {
TestMethod method = testProject.TestClasses.GetTestMethod(methodName);
if (method != null) {
MemberResolveResult resolveResult = new MemberResolveResult(null, null, method.Method);
FilePosition filePos = resolveResult.GetDefinitionPosition();
return new FileLineReference(filePos.FileName, filePos.Line, filePos.Column);
}
}
return null;
}
void ShowErrorList()
{
ShowPad(WorkbenchSingleton.Workbench.GetPad(typeof(ErrorListPad)));
}
/// <summary>
/// Runs the test for the project after a successful build.
/// </summary>
void OnBuildComplete(BuildResults results, IProject project, string namespaceFilter, IClass fixture, IMember test)
{
if (results.ErrorCount == 0 && IsRunningTest) {
UnitTestApplicationStartHelper helper = new UnitTestApplicationStartHelper();
UnitTestingOptions options = new UnitTestingOptions();
helper.NoThread = options.NoThread;
helper.NoLogo = options.NoLogo;
helper.NoDots = options.NoDots;
helper.Labels = options.Labels;
helper.ShadowCopy = !options.NoShadow;
if (options.CreateXmlOutputFile) {
helper.XmlOutputFile = Path.Combine(Path.GetDirectoryName(project.OutputAssemblyFullPath), project.AssemblyName + "-TestResult.xml");
}
helper.Initialize(project, namespaceFilter, fixture, test);
helper.Results = Path.GetTempFileName();
ResetTestResults(project);
testResultsMonitor.FileName = helper.Results;
testResultsMonitor.Start();
try {
RunTests(helper);
} catch {
StopMonitoring();
throw;
}
} else {
if (IsRunningTest) {
Stop();
}
if (TaskService.SomethingWentWrong && ErrorListPad.ShowAfterBuild) {
ShowErrorList();
}
}
}
/// <summary>
/// Clears the test results in the test tree view for the
/// project currently being tested.
/// </summary>
void ResetTestResults(IProject project)
{
TestProject testProject = GetTestProject(project);
if (testProject != null) {
testProject.ResetTestResults();
}
}
/// <summary>
/// Clears the test results in the test tree view for all the
/// displayed projects.
/// </summary>
void ResetAllTestResults()
{
if (UnitTestsPad.Instance != null) {
UnitTestsPad.Instance.TestTreeView.ResetTestResults();
}
}
/// <summary>
/// Gets the TestProject associated with the specified project
/// from the test tree view.
/// </summary>
TestProject GetTestProject(IProject project)
{
if (UnitTestsPad.Instance != null) {
return UnitTestsPad.Instance.TestTreeView.GetTestProject(project);
}
return null;
}
/// <summary>
/// Updates the test result in the test tree view.
/// </summary>
void UpdateTestResult(TestResult result)
{
TestProject testProject = GetTestProject(currentProject);
if (testProject != null) {
testProject.UpdateTestResult(result);
}
}
void StopMonitoring()
{
try {
File.Delete(testResultsMonitor.FileName);
} catch { }
testResultsMonitor.Dispose();
}
void TestFinished(object source, TestFinishedEventArgs e)
{
WorkbenchSingleton.SafeThreadAsyncCall(ShowResult, e.Result);
}
}
/// <summary>
/// Custom build command that makes sure errors and warnings
/// are not cleared from the Errors list before every build since
/// we may be running multiple tests after each other.
/// </summary>
public class BuildProjectBeforeTestRun : BuildProjectBeforeExecute
{
public BuildProjectBeforeTestRun(IProject targetProject)
: base(targetProject)
{
}
/// <summary>
/// Before a build do not clear the tasks, just save any
/// dirty files.
/// </summary>
public override void BeforeBuild()
{
SaveAllFiles.SaveAll();
}
}
public class RunTestInPadCommand : AbstractRunTestCommand
{
ProcessRunner runner;
public RunTestInPadCommand()
{
runner = new ProcessRunner();
runner.LogStandardOutputAndError = false;
runner.OutputLineReceived += OutputLineReceived;
runner.ProcessExited += ProcessExited;
}
protected override void RunTests(UnitTestApplicationStartHelper helper)
{
TestRunnerCategory.AppendLine(helper.GetCommandLine());
runner.Start(helper.UnitTestApplication, helper.GetArguments());
}
protected override void OnStop()
{
runner.Kill();
}
protected ProcessRunner GetProcessRunner()
{
return runner;
}
void OutputLineReceived(object source, LineReceivedEventArgs e)
{
TestRunnerCategory.AppendLine(e.Line);
}
void ProcessExited(object source, EventArgs e)
{
WorkbenchSingleton.SafeThreadAsyncCall(TestsFinished);
}
void TestFinished(object source, TestFinishedEventArgs e)
{
WorkbenchSingleton.SafeThreadAsyncCall(ShowResult, e.Result);
}
}
public class RunTestWithDebuggerCommand : AbstractRunTestCommand
{
public override void Run()
{
if (DebuggerService.IsDebuggerLoaded && DebuggerService.CurrentDebugger.IsDebugging) {
if (MessageService.AskQuestion("${res:XML.MainMenu.RunMenu.Compile.StopDebuggingQuestion}",
"${res:XML.MainMenu.RunMenu.Compile.StopDebuggingTitle}"))
{
DebuggerService.CurrentDebugger.Stop();
base.Run();
}
} else {
base.Run();
}
}
protected override void RunTests(UnitTestApplicationStartHelper helper)
{
bool running = false;
try {
TestRunnerCategory.AppendLine(helper.GetCommandLine());
ProcessStartInfo startInfo = new ProcessStartInfo(helper.UnitTestApplication);
startInfo.Arguments = helper.GetArguments();
startInfo.WorkingDirectory = UnitTestApplicationStartHelper.UnitTestApplicationDirectory;
DebuggerService.DebugStopped += DebuggerFinished;
DebuggerService.CurrentDebugger.Start(startInfo);
running = true;
} finally {
if (!running) {
DebuggerService.DebugStopped -= DebuggerFinished;
}
}
}
protected override void OnStop()
{
if (DebuggerService.CurrentDebugger.IsDebugging) {
DebuggerService.CurrentDebugger.Stop();
}
}
void DebuggerFinished(object sender, EventArgs e)
{
DebuggerService.DebugStopped -= DebuggerFinished;
WorkbenchSingleton.SafeThreadAsyncCall(TestsFinished);
}
}
public class RunAllTestsInPadCommand : RunTestInPadCommand
{
public override void Run()
{
// To make sure all tests are run we set the Owner to null.
Owner = null;
base.Run();
}
}
public class RunProjectTestsInPadCommand : RunTestInPadCommand, ITestTreeView
{
public override void Run()
{
Owner = this;
base.Run();
}
public IMember SelectedMethod {
get { return null; }
}
public IClass SelectedClass {
get { return null; }
}
public IProject SelectedProject {
get { return ProjectService.CurrentProject; }
}
public string SelectedNamespace {
get { return null; }
}
}
}

26
src/AddIns/Analysis/UnitTesting/Src/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/Src/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);
}
}
}

19
src/AddIns/Analysis/UnitTesting/Src/RunningTestsCondition.cs

@ -1,19 +0,0 @@ @@ -1,19 +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
{
/// <summary>
/// Determines whether #develop is currently running unit tests.
/// </summary>
public class RunningTestsCondition : IConditionEvaluator
{
public bool IsValid(object caller, Condition condition)
{
return AbstractRunTestCommand.IsRunningTest;
}
}
}

214
src/AddIns/Analysis/UnitTesting/Src/TestClassCollection.cs

@ -1,214 +0,0 @@ @@ -1,214 +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.Collections.ObjectModel;
using ICSharpCode.Core;
namespace ICSharpCode.UnitTesting
{
public class TestClassCollection : KeyedCollection<string, TestClass>
{
TestResultType testResult = TestResultType.None;
Dictionary<string, TestClass> passedTestClasses = new Dictionary<string, TestClass>();
Dictionary<string, TestClass> failedTestClasses = new Dictionary<string, TestClass>();
Dictionary<string, TestClass> ignoredTestClasses = new Dictionary<string, TestClass>();
/// <summary>
/// Raised when the test result for this collection of
/// classes has changed.
/// </summary>
public event EventHandler ResultChanged;
/// <summary>
/// Raised when a class is added to this collection.
/// </summary>
public event TestClassEventHandler TestClassAdded;
/// <summary>
/// Raised when a class is removed from this collection.
/// </summary>
public event TestClassEventHandler TestClassRemoved;
/// <summary>
/// Gets the overall test results for the collection of
/// test classes.
/// </summary>
public TestResultType Result {
get {
return testResult;
}
}
/// <summary>
/// Sets all the test class test results back to none.
/// </summary>
public void ResetTestResults()
{
passedTestClasses.Clear();
failedTestClasses.Clear();
ignoredTestClasses.Clear();
foreach (TestClass c in this) {
c.ResetTestResults();
}
SetTestResult(TestResultType.None);
}
/// <summary>
/// Updates the test method with the specified test result.
/// </summary>
public void UpdateTestResult(TestResult testResult)
{
TestClass testClass = GetTestClassFromTestMemberName(testResult.Name);
if (testClass != null) {
testClass.UpdateTestResult(testResult);
}
}
/// <summary>
/// Gets the matching test member from this set of classes.
/// </summary>
/// <param name="fullyQualifiedName">The fully qualified
/// method name (e.g. Namespace.ClassName.MethodName).</param>
/// <returns>Null if the method cannot be found.</returns>
public TestMember GetTestMember(string fullyQualifiedName)
{
string className = TestMember.GetQualifiedClassName(fullyQualifiedName);
if (className != null) {
if (Contains(className)) {
TestClass testClass = this[className];
string memberName = TestMember.GetMemberName(fullyQualifiedName);
if (memberName != null) {
return testClass.GetTestMember(memberName);
}
} else {
LoggingService.Debug("TestClass not found: " + className);
}
} else {
LoggingService.Debug("Invalid test member name: " + fullyQualifiedName);
}
return null;
}
protected override string GetKeyForItem(TestClass item)
{
return item.QualifiedName;
}
protected override void InsertItem(int index, TestClass item)
{
item.ResultChanged += TestClassResultChanged;
base.InsertItem(index, item);
TestClassResultChanged(item, new EventArgs());
OnTestClassAdded(item);
}
protected override void RemoveItem(int index)
{
TestClass c = this[index];
c.ResultChanged -= TestClassResultChanged;
base.RemoveItem(index);
OnTestResultNone(c.Name);
OnTestClassRemoved(c);
}
protected void OnTestClassAdded(TestClass testClass)
{
if (TestClassAdded != null) {
TestClassAdded(this, new TestClassEventArgs(testClass));
}
}
protected void OnTestClassRemoved(TestClass testClass)
{
if (TestClassRemoved != null) {
TestClassRemoved(this, new TestClassEventArgs(testClass));
}
}
void TestClassResultChanged(object source, EventArgs e)
{
TestClass c = (TestClass)source;
switch (c.Result) {
case TestResultType.None:
OnTestResultNone(c.QualifiedName);
break;
case TestResultType.Failure:
SetTestResult(TestResultType.Failure);
failedTestClasses.Add(c.QualifiedName, c);
break;
case TestResultType.Success:
passedTestClasses.Add(c.QualifiedName, c);
if (passedTestClasses.Count == Count) {
SetTestResult(TestResultType.Success);
} else if (passedTestClasses.Count + ignoredTestClasses.Count == Count) {
SetTestResult(TestResultType.Ignored);
}
break;
case TestResultType.Ignored:
ignoredTestClasses.Add(c.QualifiedName, c);
if (ignoredTestClasses.Count == Count ||
ignoredTestClasses.Count + passedTestClasses.Count == Count) {
SetTestResult(TestResultType.Ignored);
}
break;
}
}
void SetTestResult(TestResultType value)
{
TestResultType previousTestResult = testResult;
testResult = value;
if (testResult != previousTestResult) {
OnResultChanged();
}
}
void OnResultChanged()
{
if (ResultChanged != null) {
ResultChanged(this, new EventArgs());
}
}
/// <summary>
/// Removes the specified test class from the list of
/// failed, passed and ignored tests and updates the
/// test result state of the test class collection.
/// </summary>
void OnTestResultNone(string qualifiedName)
{
passedTestClasses.Remove(qualifiedName);
failedTestClasses.Remove(qualifiedName);
ignoredTestClasses.Remove(qualifiedName);
if (ignoredTestClasses.Count + failedTestClasses.Count == 0) {
SetTestResult(TestResultType.None);
}
}
/// <summary>
/// Gets the test class from the specified test result.
/// </summary>
TestClass GetTestClassFromTestMemberName(string memberName)
{
if (memberName != null) {
string className = TestMember.GetQualifiedClassName(memberName);
if (className != null) {
if (Contains(className)) {
return this[className];
} else {
LoggingService.Debug("TestClass not found: " + className);
return GetTestClassFromTestMemberName(className);
}
} else {
LoggingService.Debug("Invalid TestMember.Name: " + memberName);
}
}
return null;
}
}
}

30
src/AddIns/Analysis/UnitTesting/Src/TestClassEventArgs.cs

@ -1,30 +0,0 @@ @@ -1,30 +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
{
/// <summary>
/// Represents the class that will handle the TestCollection's
/// TestClassAdded or TestClassRemoved events.
/// </summary>
public delegate void TestClassEventHandler(object source, TestClassEventArgs e);
/// <summary>
/// Provides data for the TestCollection's TestClassAdded and TestClassRemoved events.
/// </summary>
public class TestClassEventArgs
{
TestClass testClass;
public TestClassEventArgs(TestClass testClass)
{
this.testClass = testClass;
}
public TestClass TestClass {
get { return testClass; }
}
}
}

108
src/AddIns/Analysis/UnitTesting/Src/TestDebuggerBase.cs

@ -1,108 +0,0 @@ @@ -1,108 +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.Debugging;
namespace ICSharpCode.UnitTesting
{
public abstract class TestDebuggerBase : TestRunnerBase
{
IUnitTestDebuggerService debuggerService;
IUnitTestMessageService messageService;
IDebugger debugger;
ITestResultsMonitor testResultsMonitor;
public TestDebuggerBase()
: this(new UnitTestDebuggerService(),
new UnitTestMessageService(),
new TestResultsMonitor())
{
}
public TestDebuggerBase(IUnitTestDebuggerService debuggerService,
IUnitTestMessageService messageService,
ITestResultsMonitor testResultsMonitor)
{
this.debuggerService = debuggerService;
this.messageService = messageService;
this.testResultsMonitor = testResultsMonitor;
this.debugger = debuggerService.CurrentDebugger;
testResultsMonitor.TestFinished += OnTestFinished;
}
protected ITestResultsMonitor TestResultsMonitor {
get { return testResultsMonitor; }
}
public override void Start(SelectedTests selectedTests)
{
ProcessStartInfo startInfo = GetProcessStartInfo(selectedTests);
if (IsDebuggerRunning) {
if (CanStopDebugging()) {
debugger.Stop();
Start(startInfo);
}
} else {
Start(startInfo);
}
}
public bool IsDebuggerRunning {
get { return debuggerService.IsDebuggerLoaded && debugger.IsDebugging; }
}
bool CanStopDebugging()
{
string question = "${res:XML.MainMenu.RunMenu.Compile.StopDebuggingQuestion}";
string caption = "${res:XML.MainMenu.RunMenu.Compile.StopDebuggingTitle}";
return messageService.AskQuestion(question, caption);
}
void Start(ProcessStartInfo startInfo)
{
testResultsMonitor.Start();
StartDebugger(startInfo);
}
void StartDebugger(ProcessStartInfo startInfo)
{
LogCommandLine(startInfo);
bool running = false;
debugger.DebugStopped += DebugStopped;
try {
debugger.Start(startInfo);
running = true;
} finally {
if (!running) {
debugger.DebugStopped -= DebugStopped;
}
}
}
void DebugStopped(object source, EventArgs e)
{
debugger.DebugStopped -= DebugStopped;
OnAllTestsFinished(source, e);
}
public override void Stop()
{
if (debugger.IsDebugging) {
debugger.Stop();
}
testResultsMonitor.Stop();
testResultsMonitor.Read();
}
public override void Dispose()
{
Stop();
testResultsMonitor.Dispose();
}
}
}

23
src/AddIns/Analysis/UnitTesting/Src/TestFinishedEventArgs.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;
namespace ICSharpCode.UnitTesting
{
public delegate void TestFinishedEventHandler(object source, TestFinishedEventArgs e);
public class TestFinishedEventArgs : EventArgs
{
TestResult result;
public TestFinishedEventArgs(TestResult result)
{
this.result = result;
}
public TestResult Result {
get { return result; }
}
}
}

90
src/AddIns/Analysis/UnitTesting/Src/TestFrameworkDescriptor.cs

@ -1,90 +0,0 @@ @@ -1,90 +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 ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
public class TestFrameworkDescriptor
{
Properties properties;
ITestFrameworkFactory factory;
ITestFramework testFramework;
List<string> supportedProjectFileExtensions = new List<string>();
public TestFrameworkDescriptor(Properties properties, ITestFrameworkFactory factory)
{
this.properties = properties;
this.factory = factory;
GetSupportedProjectFileExtensions();
}
void GetSupportedProjectFileExtensions()
{
string extensions = properties["supportedProjects"];
foreach (string extension in extensions.Split(';')) {
supportedProjectFileExtensions.Add(extension.ToLowerInvariant().Trim());
}
}
public string Id {
get { return properties["id"]; }
}
public ITestFramework TestFramework {
get {
CreateTestFrameworkIfNotCreated();
return testFramework;
}
}
void CreateTestFrameworkIfNotCreated()
{
if (testFramework == null) {
testFramework = factory.Create(ClassName);
}
}
string ClassName {
get { return properties["class"]; }
}
public bool IsSupportedProject(IProject project)
{
if (IsSupportedProjectFileExtension(project)) {
return IsSupportedByTestFramework(project);
}
return false;
}
bool IsSupportedProjectFileExtension(IProject project)
{
string extension = GetProjectFileExtension(project);
return IsSupportedProjectFileExtension(extension);
}
string GetProjectFileExtension(IProject project)
{
if (project != null) {
return Path.GetExtension(project.FileName).ToLowerInvariant();
}
return null;
}
bool IsSupportedProjectFileExtension(string extension)
{
return supportedProjectFileExtensions.Contains(extension);
}
bool IsSupportedByTestFramework(IProject project)
{
return TestFramework.IsTestProject(project);
}
}
}

30
src/AddIns/Analysis/UnitTesting/Src/TestFrameworkDoozer.cs

@ -1,30 +0,0 @@ @@ -1,30 +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;
using ICSharpCode.Core;
namespace ICSharpCode.UnitTesting
{
public class TestFrameworkDoozer : IDoozer
{
public TestFrameworkDoozer()
{
}
public bool HandleConditions {
get { return false; }
}
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);
}
}
}

23
src/AddIns/Analysis/UnitTesting/Src/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;
}
}
}

153
src/AddIns/Analysis/UnitTesting/Src/TestMemberCollection.cs

@ -1,153 +0,0 @@ @@ -1,153 +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.Collections.ObjectModel;
namespace ICSharpCode.UnitTesting
{
public class TestMemberCollection : KeyedCollection<string, TestMember>
{
TestResultType testResult = TestResultType.None;
Dictionary<string, TestMember> passedTestMembers = new Dictionary<string, TestMember>();
Dictionary<string, TestMember> failedTestMembers = new Dictionary<string, TestMember>();
Dictionary<string, TestMember> ignoredTestMembers = new Dictionary<string, TestMember>();
/// <summary>
/// Raised when the test result for this collection of
/// members has changed.
/// </summary>
public event EventHandler ResultChanged;
/// <summary>
/// Raised when a member is added to this collection.
/// </summary>
public event TestMemberEventHandler TestMemberAdded;
/// <summary>
/// Raised when a member is removed from this collection.
/// </summary>
public event TestMemberEventHandler TestMemberRemoved;
/// <summary>
/// Gets the overall test results for the collection of
/// test members.
/// </summary>
public TestResultType Result {
get { return testResult; }
}
/// <summary>
/// Sets all the test members test results back to none.
/// </summary>
public void ResetTestResults()
{
passedTestMembers.Clear();
failedTestMembers.Clear();
ignoredTestMembers.Clear();
foreach (TestMember member in this) {
member.Result = TestResultType.None;
}
SetTestResult(TestResultType.None);
}
protected override void InsertItem(int index, TestMember item)
{
item.ResultChanged += TestMemberResultChanged;
base.InsertItem(index, item);
TestMemberResultChanged(item, new EventArgs());
OnTestMemberAdded(item);
}
protected override string GetKeyForItem(TestMember item)
{
return item.Name;
}
protected override void RemoveItem(int index)
{
TestMember member = this[index];
member.ResultChanged -= TestMemberResultChanged;
base.RemoveItem(index);
OnTestResultNone(member.Name);
OnTestMemberRemoved(member);
}
protected void OnTestMemberAdded(TestMember testMember)
{
if (TestMemberAdded != null) {
TestMemberAdded(this, new TestMemberEventArgs(testMember));
}
}
protected void OnTestMemberRemoved(TestMember testMember)
{
if (TestMemberRemoved != null) {
TestMemberRemoved(this, new TestMemberEventArgs(testMember));
}
}
void TestMemberResultChanged(object source, EventArgs e)
{
TestMember member = (TestMember)source;
switch (member.Result) {
case TestResultType.None:
OnTestResultNone(member.Name);
break;
case TestResultType.Failure:
SetTestResult(TestResultType.Failure);
failedTestMembers.Add(member.Name, member);
break;
case TestResultType.Success:
passedTestMembers.Add(member.Name, member);
if (passedTestMembers.Count == Count) {
SetTestResult(TestResultType.Success);
} else if (passedTestMembers.Count + ignoredTestMembers.Count == Count) {
SetTestResult(TestResultType.Ignored);
}
break;
case TestResultType.Ignored:
ignoredTestMembers.Add(member.Name, member);
if (ignoredTestMembers.Count == Count ||
ignoredTestMembers.Count + passedTestMembers.Count == Count) {
SetTestResult(TestResultType.Ignored);
}
break;
}
}
void SetTestResult(TestResultType value)
{
TestResultType previousTestResult = testResult;
testResult = value;
if (testResult != previousTestResult) {
OnResultChanged();
}
}
void OnResultChanged()
{
if (ResultChanged != null) {
ResultChanged(this, new EventArgs());
}
}
/// <summary>
/// Removes the specified test member from the list of
/// failed, passed and ignored tests and updates the
/// test result state of the test members collection.
/// </summary>
void OnTestResultNone(string name)
{
passedTestMembers.Remove(name);
failedTestMembers.Remove(name);
ignoredTestMembers.Remove(name);
if (ignoredTestMembers.Count + failedTestMembers.Count == 0) {
SetTestResult(TestResultType.None);
}
}
}
}

30
src/AddIns/Analysis/UnitTesting/Src/TestMemberEventArgs.cs

@ -1,30 +0,0 @@ @@ -1,30 +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
{
/// <summary>
/// Represents the member that will handle the TestCollection's
/// TestMemberAdded or TestMemberRemoved events.
/// </summary>
public delegate void TestMemberEventHandler(object source, TestMemberEventArgs e);
/// <summary>
/// Provides data for the TestCollection's TestMemberAdded and TestMemberRemoved events.
/// </summary>
public class TestMemberEventArgs
{
TestMember testMember;
public TestMemberEventArgs(TestMember testMember)
{
this.testMember = testMember;
}
public TestMember TestMember {
get { return testMember; }
}
}
}

55
src/AddIns/Analysis/UnitTesting/Src/TestMethodTreeNode.cs

@ -1,55 +0,0 @@ @@ -1,55 +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.Dom;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// Represents a method that has the [Test] attribute associated with it.
/// </summary>
public class TestMethodTreeNode : TestTreeNode
{
TestMethod testMethod;
public TestMethodTreeNode(TestProject project, TestMethod testMethod)
: base(project, testMethod.Name)
{
this.testMethod = testMethod;
testMethod.ResultChanged += TestMethodResultChanged;
UpdateImageListIndex(testMethod.Result);
}
/// <summary>
/// Gets the underlying IMethod for this test method.
/// </summary>
public IMember Method {
get {
return testMethod.Method;
}
}
/// <summary>
/// Removes the TestMethod.ResultChanged event handler.
/// </summary>
public override void Dispose()
{
if (!IsDisposed) {
testMethod.ResultChanged -= TestMethodResultChanged;
}
base.Dispose();
}
/// <summary>
/// Updates the node's icon after the test method result
/// has changed.
/// </summary>
void TestMethodResultChanged(object source, EventArgs e)
{
UpdateImageListIndex(testMethod.Result);
}
}
}

109
src/AddIns/Analysis/UnitTesting/Src/TestProcessRunnerBase.cs

@ -1,109 +0,0 @@ @@ -1,109 +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.Core.WinForms;
using ICSharpCode.SharpDevelop.Util;
namespace ICSharpCode.UnitTesting
{
public class TestProcessRunnerBase : TestRunnerBase
{
IUnitTestProcessRunner processRunner;
ITestResultsMonitor testResultsMonitor;
IFileSystem fileSystem;
IUnitTestMessageService messageService;
public TestProcessRunnerBase()
: this(new UnitTestProcessRunner(),
new TestResultsMonitor(),
new UnitTestFileService(),
new UnitTestMessageService())
{
}
public TestProcessRunnerBase(TestProcessRunnerBaseContext context)
: this(context.TestProcessRunner,
context.TestResultsMonitor,
context.FileSystem,
context.MessageService)
{
}
public TestProcessRunnerBase(IUnitTestProcessRunner processRunner,
ITestResultsMonitor testResultsMonitor,
IFileSystem fileSystem,
IUnitTestMessageService messageService)
{
this.processRunner = processRunner;
this.testResultsMonitor = testResultsMonitor;
this.fileSystem = fileSystem;
this.messageService = messageService;
processRunner.LogStandardOutputAndError = false;
processRunner.OutputLineReceived += OutputLineReceived;
processRunner.ErrorLineReceived += OutputLineReceived;
processRunner.ProcessExited += OnAllTestsFinished;
testResultsMonitor.TestFinished += OnTestFinished;
}
protected ITestResultsMonitor TestResultsMonitor {
get { return testResultsMonitor; }
}
protected IUnitTestProcessRunner ProcessRunner {
get { return processRunner; }
}
void OutputLineReceived(object source, LineReceivedEventArgs e)
{
OnMessageReceived(e.Line);
}
public override void Start(SelectedTests selectedTests)
{
ProcessStartInfo startInfo = GetProcessStartInfo(selectedTests);
Start(startInfo);
}
void Start(ProcessStartInfo processStartInfo)
{
LogCommandLine(processStartInfo);
if (ApplicationFileNameExists(processStartInfo.FileName)) {
testResultsMonitor.Start();
processRunner.WorkingDirectory = processStartInfo.WorkingDirectory;
processRunner.Start(processStartInfo.FileName, processStartInfo.Arguments);
} else {
ShowApplicationDoesNotExistMessage(processStartInfo.FileName);
}
}
bool ApplicationFileNameExists(string fileName)
{
return fileSystem.FileExists(fileName);
}
void ShowApplicationDoesNotExistMessage(string fileName)
{
string resourceString = "${res:ICSharpCode.UnitTesting.TestRunnerNotFoundMessageFormat}";
messageService.ShowFormattedErrorMessage(resourceString, fileName);
}
public override void Stop()
{
processRunner.Kill();
testResultsMonitor.Stop();
testResultsMonitor.Read();
}
public override void Dispose()
{
testResultsMonitor.Dispose();
testResultsMonitor.TestFinished -= OnTestFinished;
processRunner.ErrorLineReceived -= OutputLineReceived;
processRunner.OutputLineReceived -= OutputLineReceived;
}
}
}

52
src/AddIns/Analysis/UnitTesting/Src/TestProcessRunnerBaseContext.cs

@ -1,52 +0,0 @@ @@ -1,52 +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.WinForms;
using ICSharpCode.SharpDevelop.Util;
namespace ICSharpCode.UnitTesting
{
public class TestProcessRunnerBaseContext
{
IUnitTestProcessRunner processRunner;
ITestResultsMonitor testResultsMonitor;
IFileSystem fileSystem;
IUnitTestMessageService messageService;
public TestProcessRunnerBaseContext()
: this(new UnitTestProcessRunner(),
new TestResultsMonitor(),
new UnitTestFileService(),
new UnitTestMessageService())
{
}
public TestProcessRunnerBaseContext(IUnitTestProcessRunner processRunner,
ITestResultsMonitor testResultsMonitor,
IFileSystem fileSystem,
IUnitTestMessageService messageService)
{
this.processRunner = processRunner;
this.testResultsMonitor = testResultsMonitor;
this.fileSystem = fileSystem;
this.messageService = messageService;
}
public IUnitTestProcessRunner TestProcessRunner {
get { return processRunner; }
}
public ITestResultsMonitor TestResultsMonitor {
get { return testResultsMonitor; }
}
public IFileSystem FileSystem {
get { return fileSystem; }
}
public IUnitTestMessageService MessageService {
get { return messageService; }
}
}
}

178
src/AddIns/Analysis/UnitTesting/Src/TestResultsMonitor.cs

@ -1,178 +0,0 @@ @@ -1,178 +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.IO;
using System.Text;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// Watches for new test results as they occur. Test results
/// are written to a file and read in by this class.
/// </summary>
public class TestResultsMonitor : ITestResultsMonitor
{
FileInfo fileInfo;
TestResultsReader testResultsReader;
FileSystemWatcher fileSystemWatcher;
long initialFilePosition = 3;
long filePosition;
const int BytesBufferLength = 1024;
byte[] bytes = new byte[BytesBufferLength];
/// <summary>
/// Raised when a single test has been completed.
/// </summary>
public event TestFinishedEventHandler TestFinished;
public TestResultsMonitor(string fileName)
{
fileInfo = new FileInfo(fileName);
ResetFilePosition();
}
public TestResultsMonitor()
: this(Path.GetTempFileName())
{
ResetFilePosition();
}
public long InitialFilePosition {
get { return initialFilePosition; }
set { initialFilePosition = value; }
}
/// <summary>
/// Gets or sets the test results filename.
/// </summary>
public string FileName {
get { return fileInfo.FullName; }
set { fileInfo = new FileInfo(value); }
}
/// <summary>
/// Starts monitoring for test results.
/// </summary>
public void Start()
{
testResultsReader = new TestResultsReader();
ResetFilePosition();
string filter = fileInfo.Name;
fileSystemWatcher = new FileSystemWatcher(fileInfo.DirectoryName, filter);
if (File.Exists(fileInfo.FullName)) {
fileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;
fileSystemWatcher.Changed += FileChanged;
} else {
fileSystemWatcher.Created += FileCreated;
}
fileSystemWatcher.Error += FileSystemWatcherError;
fileSystemWatcher.EnableRaisingEvents = true;
}
/// <summary>
/// Stops monitoring.
/// </summary>
public void Stop()
{
if (fileSystemWatcher != null) {
fileSystemWatcher.Dispose();
fileSystemWatcher = null;
}
}
/// <summary>
/// Reads the rest of the file from the current position.
/// Raises the TestFinished event for each test result
/// still in the file.
/// </summary>
public void Read()
{
string text = ReadTextAdded();
if (text != null) {
TestResult[] results = testResultsReader.Read(text);
OnTestResultsReceived(results);
}
}
/// <summary>
/// Stops monitoring and releases any resources used
/// by the TestResultsMonitor.
/// </summary>
public void Dispose()
{
Stop();
try {
File.Delete(FileName);
} catch { }
}
void FileCreated(object source, FileSystemEventArgs e)
{
fileSystemWatcher.Created -= FileCreated;
fileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;
fileSystemWatcher.Changed += FileChanged;
}
void FileChanged(object source, FileSystemEventArgs e)
{
Read();
}
void OnTestResultsReceived(TestResult[] results)
{
if ((results.Length > 0) && (TestFinished != null)) {
foreach (TestResult result in results) {
TestFinished(this, new TestFinishedEventArgs(result));
}
}
}
/// <summary>
/// Reads the text added to the end of the file from the last
/// position we read from.
/// </summary>
string ReadTextAdded()
{
StringBuilder text = null;
try {
using (FileStream fs = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
if (fs.Length > 0) {
text = new StringBuilder();
int bytesRead = 0;
fs.Seek(filePosition, SeekOrigin.Begin);
do {
bytesRead = fs.Read(bytes, 0, BytesBufferLength);
if (bytesRead > 0) {
filePosition += bytesRead;
text.Append(UTF8Encoding.UTF8.GetString(bytes, 0, bytesRead));
}
} while ((bytesRead > 0) && (filePosition < fs.Length));
}
}
} catch (FileNotFoundException) {
// Test was aborted before it even started execution
return null;
}
if (text != null) {
return text.ToString();
}
return null;
}
void FileSystemWatcherError(object source, ErrorEventArgs e)
{
Console.WriteLine(e.GetException().ToString());
}
void ResetFilePosition()
{
filePosition = initialFilePosition;
}
}
}

155
src/AddIns/Analysis/UnitTesting/Src/TestResultsReader.cs

@ -1,155 +0,0 @@ @@ -1,155 +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.Text;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// Reads the test results file produced by the custom
/// nunit-console application.
/// </summary>
public class TestResultsReader
{
StringBuilder nameBuilder = new StringBuilder();
StringBuilder valueBuilder = new StringBuilder();
bool firstNameChar = true;
TestResult result;
enum State {
WaitingForEndOfName = 0,
WaitingForStartOfValue = 1,
WaitingForEndOfValue = 2
}
State state = State.WaitingForEndOfName;
public TestResultsReader()
{
}
/// <summary>
/// Returns any TestResults that are in the text.
/// </summary>
/// <param name="text">The text read in from the
/// TestResults file.</param>
public TestResult[] Read(string text)
{
List<TestResult> results = new List<TestResult>();
foreach (char ch in text) {
if (ReadNameValuePair(ch)) {
if (ReadTestResult()) {
results.Add(result);
}
}
}
return results.ToArray();
}
/// <summary>
/// Reads a name-value pair of the form:
///
/// Name: Value
///
/// A value can span multiple lines:
///
/// Name1: ValueLine1
/// {SP}ValueLine2
/// {SP}ValueLine3
/// Name1: Value2
///
/// Each continued line of the value must start with
/// a single space character to distinguish it from
/// the start of a new name-value pair.
/// </summary>
/// <returns>True if a name-value pair has been
/// successfully read in</returns>
bool ReadNameValuePair(char ch)
{
if (state == State.WaitingForEndOfName) {
ReadNameChar(ch);
} else if (state == State.WaitingForStartOfValue) {
// Makes sure first space is ignored.
state = State.WaitingForEndOfValue;
} else {
return ReadValueChar(ch);
}
return false;
}
void ReadNameChar(char ch)
{
if (ch == ':') {
state = State.WaitingForStartOfValue;
} else if (ch == '\r' || ch == '\n') {
nameBuilder = new StringBuilder();
} else if (ch == ' ' && firstNameChar) {
state = State.WaitingForEndOfValue;
valueBuilder.Append("\r\n");
} else if (firstNameChar) {
firstNameChar = false;
nameBuilder = new StringBuilder();
valueBuilder = new StringBuilder();
nameBuilder.Append(ch);
} else {
nameBuilder.Append(ch);
}
}
bool ReadValueChar(char ch)
{
if (ch == '\r') {
// Ignore.
} else if (ch == '\n') {
state = State.WaitingForEndOfName;
firstNameChar = true;
return true;
} else {
valueBuilder.Append(ch);
}
return false;
}
/// <summary>
/// Creates and updates a TestResult based on the
/// name-value pair read in,
/// </summary>
/// <returns>True if a TestResult is ready to be returned
/// to the caller.</returns>
/// <remarks>
/// The first name-value pair for a test result is the
/// test name. The last name-value pair is the result of
/// the test (Success, Failure or Ignored).</remarks>
bool ReadTestResult()
{
string name = nameBuilder.ToString();
if (name == "Name") {
result = new TestResult(valueBuilder.ToString());
} else if (result != null) {
if (name == "Message") {
result.Message = valueBuilder.ToString();
} else if (name == "StackTrace") {
result.StackTrace = valueBuilder.ToString();
} else if (name == "Result") {
UpdateTestSuccess();
return true;
}
}
return false;
}
void UpdateTestSuccess()
{
string value = valueBuilder.ToString();
if (value == "Success") {
result.ResultType = TestResultType.Success;
} else if (value == "Failure") {
result.ResultType = TestResultType.Failure;
} else {
result.ResultType = TestResultType.Ignored;
}
}
}
}

68
src/AddIns/Analysis/UnitTesting/Src/TestRunnerBase.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 System.Diagnostics;
namespace ICSharpCode.UnitTesting
{
public abstract class TestRunnerBase : ITestRunner
{
public TestRunnerBase()
{
}
protected virtual ProcessStartInfo GetProcessStartInfo(SelectedTests selectedTests)
{
return new ProcessStartInfo();
}
protected void LogCommandLine(ProcessStartInfo startInfo)
{
string commandLine = GetCommandLine(startInfo);
OnMessageReceived(commandLine);
}
protected string GetCommandLine(ProcessStartInfo startInfo)
{
return String.Format("\"{0}\" {1}", startInfo.FileName, startInfo.Arguments);
}
public event EventHandler AllTestsFinished;
protected void OnAllTestsFinished(object source, EventArgs e)
{
if (AllTestsFinished != null) {
AllTestsFinished(source, e);
}
}
public event TestFinishedEventHandler TestFinished;
protected void OnTestFinished(object source, TestFinishedEventArgs e)
{
if (TestFinished != null) {
TestResult testResult = CreateTestResultForTestFramework(e.Result);
TestFinished(source, new TestFinishedEventArgs(testResult));
}
}
protected virtual TestResult CreateTestResultForTestFramework(TestResult testResult)
{
return testResult;
}
public event MessageReceivedEventHandler MessageReceived;
protected virtual void OnMessageReceived(string message)
{
if (MessageReceived != null) {
MessageReceived(this, new MessageReceivedEventArgs(message));
}
}
public abstract void Dispose();
public abstract void Stop();
public abstract void Start(SelectedTests selectedTests);
}
}

47
src/AddIns/Analysis/UnitTesting/Src/TestService.cs

@ -1,47 +0,0 @@ @@ -1,47 +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.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) {
UnitTestAddInTree addInTree = new UnitTestAddInTree();
testFrameworks = new RegisteredTestFrameworks(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}");
}
}
}

17
src/AddIns/Analysis/UnitTesting/Src/UnitTestAddInTree.cs

@ -1,17 +0,0 @@ @@ -1,17 +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.Core;
namespace ICSharpCode.UnitTesting
{
public class UnitTestAddInTree : IAddInTree
{
public List<T> BuildItems<T>(string path, object caller)
{
return AddInTree.BuildItems<T>(path, caller);
}
}
}

221
src/AddIns/Analysis/UnitTesting/Src/UnitTestApplicationStartHelper.cs

@ -1,221 +0,0 @@ @@ -1,221 +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.Text;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// Helper to run the unit testing console application.
/// </summary>
public class UnitTestApplicationStartHelper
{
/// <summary>
/// returns full/path/to/Tools/NUnit
/// </summary>
public static string UnitTestApplicationDirectory {
get {
return Path.Combine(FileUtility.ApplicationRootPath, @"bin\Tools\NUnit");
}
}
/// <summary>
/// returns full/path/to/Tools/NUnit/nunit-console.exe (or whichever nunit-console exe is right
/// for the project - there are different .exes for .NET 4.0 and for x86-only projects.
/// </summary>
public string UnitTestApplication {
get {
string exe = "nunit-console";
if (ProjectUsesDotnet20Runtime(project)) {
exe += "-dotnet2";
}
if (IsPlatformTarget32Bit(project)) {
exe += "-x86";
}
exe += ".exe";
return Path.Combine(UnitTestApplicationDirectory, exe);
}
}
public readonly List<string> Assemblies = new List<string>();
/// <summary>
/// Use shadow copy assemblies. Default = true.
/// </summary>
public bool ShadowCopy = true;
/// <summary>
/// Disables the use of a separate thread to run tests on separate thread. Default = false;
/// </summary>
public bool NoThread = false;
/// <summary>
/// Use /nologo directive.
/// </summary>
public bool NoLogo = false;
/// <summary>
/// Use /labels directive.
/// </summary>
public bool Labels = false;
/// <summary>
/// Use /nodots directive.
/// </summary>
public bool NoDots = false;
/// <summary>
/// File to write xml output to. Default = null.
/// </summary>
public string XmlOutputFile;
/// <summary>
/// Fixture to test. Null = test all fixtures.
/// </summary>
public string Fixture;
/// <summary>
/// Test to run. Null = run all tests. Only valid together with the Fixture property.
/// </summary>
public string Test;
/// <summary>
/// File to write test results to.
/// </summary>
public string Results;
/// <summary>
/// The namespace that tests need to be a part of if they are to
/// be run.
/// </summary>
public string NamespaceFilter;
IProject project;
public void Initialize(IProject project, IClass fixture, IMember test)
{
Initialize(project, null, fixture, test);
}
public void Initialize(IProject project, string namespaceFilter)
{
Initialize(project, namespaceFilter, null, null);
}
public void Initialize(IProject project, string namespaceFilter, IClass fixture, IMember test)
{
this.project = project;
Assemblies.Add(project.OutputAssemblyFullPath);
if (namespaceFilter != null) {
NamespaceFilter = namespaceFilter;
}
if (fixture != null) {
Fixture = fixture.DotNetName;
if (test != null) {
Test = test.Name;
}
}
}
public IProject Project {
get {
return project;
}
}
/// <summary>
/// Gets the full command line to run the unit test application.
/// This is the combination of the UnitTestApplication and
/// the command line arguments.
/// </summary>
public string GetCommandLine()
{
return String.Concat("\"", UnitTestApplication, "\" ", GetArguments());
}
/// <summary>
/// Gets the arguments to use on the command line to run NUnit.
/// </summary>
public string GetArguments()
{
StringBuilder b = new StringBuilder();
foreach (string assembly in Assemblies) {
if (b.Length > 0)
b.Append(' ');
b.Append('"');
b.Append(assembly);
b.Append('"');
}
if (!ShadowCopy)
b.Append(" /noshadow");
if (NoThread)
b.Append(" /nothread");
if (NoLogo)
b.Append(" /nologo");
if (Labels)
b.Append(" /labels");
if (NoDots)
b.Append(" /nodots");
if (XmlOutputFile != null) {
b.Append(" /xml=\"");
b.Append(XmlOutputFile);
b.Append('"');
}
if (Results != null) {
b.Append(" /results=\"");
b.Append(Results);
b.Append('"');
}
string run = null;
if (NamespaceFilter != null) {
run = NamespaceFilter;
} else if (Fixture != null) {
if (Test != null) {
run = Fixture + "." + Test;
} else {
run = Fixture;
}
} else if (Test != null) {
run = Test;
}
if (run != null) {
b.Append(" /run=\"");
b.Append(run);
b.Append('"');
}
return b.ToString();
}
/// <summary>
/// Checks that the project's PlatformTarget is x86 for the active configuration.
/// </summary>
bool IsPlatformTarget32Bit(IProject project)
{
MSBuildBasedProject msbuildProject = project as MSBuildBasedProject;
if (msbuildProject != null) {
string platformTarget = msbuildProject.GetEvaluatedProperty("PlatformTarget");
return String.Equals(platformTarget, "x86", StringComparison.OrdinalIgnoreCase);
}
return false;
}
bool ProjectUsesDotnet20Runtime(IProject project)
{
MSBuildBasedProject msbuildProject = project as MSBuildBasedProject;
if (msbuildProject != null) {
string targetFrameworkVersion = msbuildProject.GetEvaluatedProperty("TargetFrameworkVersion");
return !String.Equals(targetFrameworkVersion, "v4.0", StringComparison.OrdinalIgnoreCase);
}
return false;
}
}
}

15
src/AddIns/Analysis/UnitTesting/Src/UnitTestBuildOptions.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.Project;
namespace ICSharpCode.UnitTesting
{
public class UnitTestBuildOptions : IBuildOptions
{
public bool ShowErrorListAfterBuild {
get { return BuildOptions.ShowErrorListAfterBuild; }
}
}
}

18
src/AddIns/Analysis/UnitTesting/Src/UnitTestBuildProjectFactory.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 System.Collections.Generic;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Project.Commands;
namespace ICSharpCode.UnitTesting
{
public class UnitTestBuildProjectFactory : IBuildProjectFactory
{
public BuildProject CreateBuildProjectBeforeTestRun(IEnumerable<IProject> projects)
{
return new BuildProjectBeforeExecute(new MultipleProjectBuildable(projects));
}
}
}

19
src/AddIns/Analysis/UnitTesting/Src/UnitTestDebuggerService.cs

@ -1,19 +0,0 @@ @@ -1,19 +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.Debugging;
namespace ICSharpCode.UnitTesting
{
public class UnitTestDebuggerService : IUnitTestDebuggerService
{
public bool IsDebuggerLoaded {
get { return DebuggerService.IsDebuggerLoaded; }
}
public IDebugger CurrentDebugger {
get { return DebuggerService.CurrentDebugger; }
}
}
}

27
src/AddIns/Analysis/UnitTesting/Src/UnitTestFileService.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 System.IO;
using ICSharpCode.SharpDevelop;
namespace ICSharpCode.UnitTesting
{
public class UnitTestFileService : IUnitTestFileService
{
public void OpenFile(string fileName)
{
FileService.OpenFile(fileName);
}
public void JumpToFilePosition(string fileName, int line, int column)
{
FileService.JumpToFilePosition(fileName, line, column);
}
public bool FileExists(string fileName)
{
return File.Exists(fileName);
}
}
}

24
src/AddIns/Analysis/UnitTesting/Src/UnitTestMessageService.cs

@ -1,24 +0,0 @@ @@ -1,24 +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.Core.Services;
namespace ICSharpCode.UnitTesting
{
public class UnitTestMessageService : IUnitTestMessageService
{
public bool AskQuestion(string question, string caption)
{
return ServiceManager.Instance.MessageService.AskQuestion(question, caption);
}
public void ShowFormattedErrorMessage(string format, string item)
{
format = StringParser.Parse(format);
string message = String.Format(format, item);
ServiceManager.Instance.MessageService.ShowError(message);
}
}
}

58
src/AddIns/Analysis/UnitTesting/Src/UnitTestProcessRunner.cs

@ -1,58 +0,0 @@ @@ -1,58 +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.SharpDevelop.Util;
namespace ICSharpCode.UnitTesting
{
public class UnitTestProcessRunner : IUnitTestProcessRunner
{
ProcessRunner runner;
public event LineReceivedEventHandler OutputLineReceived {
add { runner.OutputLineReceived += value; }
remove { runner.OutputLineReceived -= value; }
}
public event LineReceivedEventHandler ErrorLineReceived {
add { runner.ErrorLineReceived += value; }
remove { runner.ErrorLineReceived -= value; }
}
public event EventHandler ProcessExited {
add { runner.ProcessExited += value; }
remove { runner.ProcessExited -= value; }
}
public UnitTestProcessRunner()
{
runner = new ProcessRunner();
}
public bool LogStandardOutputAndError {
get { return runner.LogStandardOutputAndError; }
set { runner.LogStandardOutputAndError = value; }
}
public string WorkingDirectory {
get { return runner.WorkingDirectory; }
set { runner.WorkingDirectory = value; }
}
public Dictionary<string, string> EnvironmentVariables {
get { return runner.EnvironmentVariables; }
}
public void Start(string command, string arguments)
{
runner.Start(command, arguments);
}
public void Kill()
{
runner.Kill();
}
}
}

15
src/AddIns/Analysis/UnitTesting/Src/UnitTestSaveAllFilesCommand.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;
namespace ICSharpCode.UnitTesting
{
public class UnitTestSaveAllFilesCommand : IUnitTestSaveAllFilesCommand
{
public void SaveAllFiles()
{
ICSharpCode.SharpDevelop.Commands.SaveAllFiles.SaveAll();
}
}
}

27
src/AddIns/Analysis/UnitTesting/Src/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);
}
}
}

13
src/AddIns/Analysis/UnitTesting/TestTreeView.cs

@ -26,17 +26,14 @@ namespace ICSharpCode.UnitTesting @@ -26,17 +26,14 @@ namespace ICSharpCode.UnitTesting
SourceCodeItemSelected = 1
}
/// <summary>
/// The All Tests tree root node that is added if multiple
/// test projects exist in the solution. If the solution contains
/// only one test project then no such node will be added.
/// </summary>
IRegisteredTestFrameworks testFrameworks;
public TestTreeView(IRegisteredTestFrameworks testFrameworks)
public TestTreeView(IRegisteredTestFrameworks testFrameworks, TestSolution testSolution)
{
this.testFrameworks = testFrameworks;
TestService.TestableProjects.CollectionChanged += delegate { ShowRoot = TestService.TestableProjects.Count > 1; };
// 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>
@ -58,7 +55,7 @@ namespace ICSharpCode.UnitTesting @@ -58,7 +55,7 @@ namespace ICSharpCode.UnitTesting
/// <summary>
/// Gets the member of the currently selected tree node.
/// </summary>
public TestMember SelectedMethod {
public TestMember SelectedMember {
get {
MemberUnitTestNode memberNode = SelectedItem as MemberUnitTestNode;
if (memberNode != null) {

220
src/AddIns/Analysis/UnitTesting/UnitTestApplicationStartHelper.cs

@ -1,220 +0,0 @@ @@ -1,220 +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.Text;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// Helper to run the unit testing console application.
/// </summary>
public class UnitTestApplicationStartHelper
{
/// <summary>
/// returns full/path/to/Tools/NUnit
/// </summary>
public static string UnitTestApplicationDirectory {
get {
return Path.Combine(FileUtility.ApplicationRootPath, @"bin\Tools\NUnit");
}
}
/// <summary>
/// returns full/path/to/Tools/NUnit/nunit-console.exe (or whichever nunit-console exe is right
/// for the project - there are different .exes for .NET 4.0 and for x86-only projects.
/// </summary>
public string UnitTestApplication {
get {
string exe = "nunit-console";
if (ProjectUsesDotnet20Runtime(project)) {
exe += "-dotnet2";
}
if (IsPlatformTarget32Bit(project)) {
exe += "-x86";
}
exe += ".exe";
return Path.Combine(UnitTestApplicationDirectory, exe);
}
}
public readonly List<string> Assemblies = new List<string>();
/// <summary>
/// Use shadow copy assemblies. Default = true.
/// </summary>
public bool ShadowCopy = true;
/// <summary>
/// Disables the use of a separate thread to run tests on separate thread. Default = false;
/// </summary>
public bool NoThread = false;
/// <summary>
/// Use /nologo directive.
/// </summary>
public bool NoLogo = false;
/// <summary>
/// Use /labels directive.
/// </summary>
public bool Labels = false;
/// <summary>
/// Use /nodots directive.
/// </summary>
public bool NoDots = false;
/// <summary>
/// File to write xml output to. Default = null.
/// </summary>
public string XmlOutputFile;
/// <summary>
/// Fixture to test. Null = test all fixtures.
/// </summary>
public string Fixture;
/// <summary>
/// Test to run. Null = run all tests. Only valid together with the Fixture property.
/// </summary>
public string Test;
/// <summary>
/// File to write test results to.
/// </summary>
public string Results;
/// <summary>
/// The namespace that tests need to be a part of if they are to
/// be run.
/// </summary>
public string NamespaceFilter;
IProject project;
public void Initialize(IProject project, ITypeDefinition fixture, IMethod test)
{
Initialize(project, null, fixture, test);
}
public void Initialize(IProject project, string namespaceFilter)
{
Initialize(project, namespaceFilter, null, null);
}
public void Initialize(IProject project, string namespaceFilter, ITypeDefinition fixture, IMethod test)
{
this.project = project;
Assemblies.Add(project.OutputAssemblyFullPath);
if (namespaceFilter != null) {
NamespaceFilter = namespaceFilter;
}
if (fixture != null) {
Fixture = fixture.ReflectionName;
if (test != null) {
Test = test.Name;
}
}
}
public IProject Project {
get {
return project;
}
}
/// <summary>
/// Gets the full command line to run the unit test application.
/// This is the combination of the UnitTestApplication and
/// the command line arguments.
/// </summary>
public string GetCommandLine()
{
return String.Concat("\"", UnitTestApplication, "\" ", GetArguments());
}
/// <summary>
/// Gets the arguments to use on the command line to run NUnit.
/// </summary>
public string GetArguments()
{
StringBuilder b = new StringBuilder();
foreach (string assembly in Assemblies) {
if (b.Length > 0)
b.Append(' ');
b.Append('"');
b.Append(assembly);
b.Append('"');
}
if (!ShadowCopy)
b.Append(" /noshadow");
if (NoThread)
b.Append(" /nothread");
if (NoLogo)
b.Append(" /nologo");
if (Labels)
b.Append(" /labels");
if (NoDots)
b.Append(" /nodots");
if (XmlOutputFile != null) {
b.Append(" /xml=\"");
b.Append(XmlOutputFile);
b.Append('"');
}
if (Results != null) {
b.Append(" /results=\"");
b.Append(Results);
b.Append('"');
}
string run = null;
if (NamespaceFilter != null) {
run = NamespaceFilter;
} else if (Fixture != null) {
if (Test != null) {
run = Fixture + "." + Test;
} else {
run = Fixture;
}
} else if (Test != null) {
run = Test;
}
if (run != null) {
b.Append(" /run=\"");
b.Append(run);
b.Append('"');
}
return b.ToString();
}
/// <summary>
/// Checks that the project's PlatformTarget is x86 for the active configuration.
/// </summary>
bool IsPlatformTarget32Bit(IProject project)
{
MSBuildBasedProject msbuildProject = project as MSBuildBasedProject;
if (msbuildProject != null) {
string platformTarget = msbuildProject.GetEvaluatedProperty("PlatformTarget");
return String.Equals(platformTarget, "x86", StringComparison.OrdinalIgnoreCase);
}
return false;
}
bool ProjectUsesDotnet20Runtime(IProject project)
{
MSBuildBasedProject msbuildProject = project as MSBuildBasedProject;
if (msbuildProject != null) {
string targetFrameworkVersion = msbuildProject.GetEvaluatedProperty("TargetFrameworkVersion");
return !String.Equals(targetFrameworkVersion, "v4.0", StringComparison.OrdinalIgnoreCase);
}
return false;
}
}
}

10
src/AddIns/Analysis/UnitTesting/UnitTesting.csproj

@ -66,9 +66,12 @@ @@ -66,9 +66,12 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Commands\RunTestCommands.cs" />
<Compile Include="Commands\AbstractRunTestCommand.cs" />
<Compile Include="Commands\RunAllTestsInPadCommand.cs" />
<Compile Include="Commands\RunProjectTestsInPadCommand.cs" />
<Compile Include="Commands\RunTestInPadCommand.cs" />
<Compile Include="Commands\RunTestWithDebuggerCommand.cs" />
<Compile Include="Commands\UnitTestCommands.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="Gui\EmptyUnitTestsPad.cs" />
<Compile Include="Gui\UnitTestingOptionsPanel.xaml.cs">
<DependentUpon>UnitTestingOptionsPanel.xaml</DependentUpon>
@ -92,7 +95,6 @@ @@ -92,7 +95,6 @@
<Compile Include="Interfaces\ITestRunner.cs" />
<Compile Include="Interfaces\ITestTreeView.cs" />
<Compile Include="Interfaces\IUnitTestDebuggerService.cs" />
<Compile Include="Interfaces\IUnitTestFileService.cs" />
<Compile Include="Interfaces\IUnitTestProcessRunner.cs" />
<Compile Include="Interfaces\IUnitTestSaveAllFilesCommand.cs" />
<Compile Include="Interfaces\IUnitTestsPad.cs" />
@ -101,6 +103,7 @@ @@ -101,6 +103,7 @@
<Compile Include="Model\TestClass.cs" />
<Compile Include="Model\TestMember.cs" />
<Compile Include="Model\TestProject.cs" />
<Compile Include="Model\TestSolution.cs" />
<Compile Include="MultipleProjectBuildable.cs" />
<Compile Include="Nodes\ClassUnitTestNode.cs" />
<Compile Include="Nodes\MemberUnitTestNode.cs" />
@ -134,7 +137,6 @@ @@ -134,7 +137,6 @@
<Compile Include="TestResultsReader.cs" />
<Compile Include="TestResultTask.cs" />
<Compile Include="TestTreeView.cs" />
<Compile Include="UnitTestApplicationStartHelper.cs" />
<Compile Include="UnitTestingOptions.cs" />
<Compile Include="UnitTestProcessRunner.cs" />
<None Include="PostBuildEvent.proj" />

2
src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs

@ -60,7 +60,7 @@ namespace CSharpBinding @@ -60,7 +60,7 @@ namespace CSharpBinding
inspectionManager = null;
}
if (contextActionProviders != null) {
editor.ContextActionProviders.RemoveWhere(contextActionProviders.Contains);
editor.ContextActionProviders.RemoveAll(contextActionProviders.Contains);
}
this.editor = null;
base.Detach();

4
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs

@ -137,13 +137,13 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -137,13 +137,13 @@ namespace ICSharpCode.AvalonEdit.AddIn
var highlighter = SD.EditorControlService.CreateHighlighter(document);
primaryTextEditor.SyntaxHighlighting = highlighting;
primaryTextEditor.TextArea.TextView.LineTransformers.RemoveWhere(t => t is HighlightingColorizer);
primaryTextEditor.TextArea.TextView.LineTransformers.RemoveAll(t => t is HighlightingColorizer);
primaryTextEditor.TextArea.TextView.LineTransformers.Insert(0, new HighlightingColorizer(highlighter));
primaryTextEditor.UpdateCustomizedHighlighting();
if (secondaryTextEditor != null) {
secondaryTextEditor.SyntaxHighlighting = highlighting;
secondaryTextEditor.TextArea.TextView.LineTransformers.RemoveWhere(t => t is HighlightingColorizer);
secondaryTextEditor.TextArea.TextView.LineTransformers.RemoveAll(t => t is HighlightingColorizer);
secondaryTextEditor.TextArea.TextView.LineTransformers.Insert(0, new HighlightingColorizer(highlighter));
secondaryTextEditor.UpdateCustomizedHighlighting();
}

2
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/DiffControl.xaml.cs

@ -47,7 +47,7 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -47,7 +47,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
public void CopyEditorSettings(TextEditor source)
{
string language = source.SyntaxHighlighting != null ? source.SyntaxHighlighting.Name : null;
editor.TextArea.TextView.LineTransformers.RemoveWhere(x => x is HighlightingColorizer);
editor.TextArea.TextView.LineTransformers.RemoveAll(x => x is HighlightingColorizer);
editor.TextArea.TextView.LineTransformers.Insert(0, new CustomizableHighlightingColorizer(source.SyntaxHighlighting, CustomizedHighlightingColor.FetchCustomizations(language)));
CustomizableHighlightingColorizer.ApplyCustomizationsToDefaultElements(editor, CustomizedHighlightingColor.FetchCustomizations(language));
HighlightingOptions.ApplyToRendering(editor, CustomizedHighlightingColor.FetchCustomizations(language));

21
src/Libraries/NRefactory/ICSharpCode.NRefactory/Utils/KeyComparer.cs

@ -27,6 +27,21 @@ namespace ICSharpCode.NRefactory.Utils @@ -27,6 +27,21 @@ namespace ICSharpCode.NRefactory.Utils
{
return new KeyComparer<TElement, TKey>(keySelector, Comparer<TKey>.Default, EqualityComparer<TKey>.Default);
}
public static KeyComparer<TElement, TKey> Create<TElement, TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, IEqualityComparer<TKey> equalityComparer)
{
return new KeyComparer<TElement, TKey>(keySelector, comparer, equalityComparer);
}
public static IComparer<TElement> Create<TElement, TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer)
{
return new KeyComparer<TElement, TKey>(keySelector, comparer, EqualityComparer<TKey>.Default);
}
public static IEqualityComparer<TElement> Create<TElement, TKey>(Func<TElement, TKey> keySelector, IEqualityComparer<TKey> equalityComparer)
{
return new KeyComparer<TElement, TKey>(keySelector, Comparer<TKey>.Default, equalityComparer);
}
}
public class KeyComparer<TElement, TKey> : IComparer<TElement>, IEqualityComparer<TElement>
@ -37,6 +52,12 @@ namespace ICSharpCode.NRefactory.Utils @@ -37,6 +52,12 @@ namespace ICSharpCode.NRefactory.Utils
public KeyComparer(Func<TElement, TKey> keySelector, IComparer<TKey> keyComparer, IEqualityComparer<TKey> keyEqualityComparer)
{
if (keySelector == null)
throw new ArgumentNullException("keySelector");
if (keyComparer == null)
throw new ArgumentNullException("keyComparer");
if (keyEqualityComparer == null)
throw new ArgumentNullException("keyEqualityComparer");
this.keySelector = keySelector;
this.keyComparer = keyComparer;
this.keyEqualityComparer = keyEqualityComparer;

2
src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/GacReferencePanel.cs

@ -138,7 +138,7 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -138,7 +138,7 @@ namespace ICSharpCode.SharpDevelop.Gui
void SearchItems(string text)
{
var searchList = listView.Items.OfType<ListViewItem>().ToList();
searchList.RemoveWhere(item => item.Text.IndexOf(text, StringComparison.OrdinalIgnoreCase) < 0);
searchList.RemoveAll(item => item.Text.IndexOf(text, StringComparison.OrdinalIgnoreCase) < 0);
resultList = searchList;
}

4
src/Main/Base/Project/Src/Services/ParserService/ParseInformationEventArgs.cs

@ -58,12 +58,12 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -58,12 +58,12 @@ namespace ICSharpCode.SharpDevelop.Parser
}
[Obsolete]
public IUnresolvedFile OldSyntaxTree {
public IUnresolvedFile OldCompilationUnit {
get { return this.OldUnresolvedFile; }
}
[Obsolete]
public IUnresolvedFile NewSyntaxTree {
public IUnresolvedFile NewCompilationUnit {
get { return this.NewUnresolvedFile; }
}

281
src/Main/Base/Project/Src/Util/ExtensionMethods.cs

@ -34,6 +34,7 @@ namespace ICSharpCode.SharpDevelop @@ -34,6 +34,7 @@ namespace ICSharpCode.SharpDevelop
/// </summary>
public static class ExtensionMethods
{
#region RaiseEvent
/// <summary>
/// Raises the event.
/// Does nothing if eventHandler is null.
@ -71,7 +72,9 @@ namespace ICSharpCode.SharpDevelop @@ -71,7 +72,9 @@ namespace ICSharpCode.SharpDevelop
eventHandler(sender, e);
}
}
#endregion
#region Task Extensions
/// <summary>
/// If the task throws an exception, notifies the message service.
/// Call this method on asynchronous tasks if you do not care about the result, but do not want
@ -89,7 +92,9 @@ namespace ICSharpCode.SharpDevelop @@ -89,7 +92,9 @@ namespace ICSharpCode.SharpDevelop
}
}, TaskContinuationOptions.OnlyOnFaulted);
}
#endregion
#region Collections
/// <summary>
/// Obsolete. Please use a regular foreach loop instead. ForEach() is executed for its side-effects, and side-effects mix poorly with a functional programming style.
/// </summary>
@ -138,6 +143,52 @@ namespace ICSharpCode.SharpDevelop @@ -138,6 +143,52 @@ namespace ICSharpCode.SharpDevelop
return ret;
}
public static int BinarySearch<T, K>(this IList<T> list, K key, Func<T, K> keySelector, IComparer<K> keyComparer = null)
{
return BinarySearch(list, 0, list.Count, key, keySelector, keyComparer);
}
/// <summary>
/// Searches a sorted list
/// </summary>
/// <param name="list"></param>
/// <param name="index"></param>
/// <param name="length"></param>
/// <param name="key"></param>
/// <param name="keySelector">Function that maps list items to their sort key</param>
/// <param name="keyComparer">Comparer used for the sort</param>
/// <returns></returns>
public static int BinarySearch<T, K>(this IList<T> list, int index, int length, K key, Func<T, K> keySelector, IComparer<K> keyComparer = null)
{
if (keyComparer == null)
keyComparer = Comparer<K>.Default;
int low = index;
int high = index + length - 1;
while (low <= high) {
int mid = low + (high - low >> 1);
int r = keyComparer.Compare(keySelector(list[mid]), key);
if (r == 0) {
return mid;
} else if (r < 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return ~low;
}
/// <summary>
/// Inserts an item into a sorted list.
/// </summary>
public static void OrderedInsert<T>(this IList<T> list, T item, IComparer<T> comparer)
{
int pos = BinarySearch(list, item, x => x, comparer);
if (pos < 0)
pos = ~pos;
list.Insert(pos, item);
}
public static IEnumerable<WinForms.Control> GetRecursive(this WinForms.Control.ControlCollection collection)
{
return collection.Cast<WinForms.Control>().Flatten(c => c.Controls.Cast<WinForms.Control>());
@ -154,6 +205,91 @@ namespace ICSharpCode.SharpDevelop @@ -154,6 +205,91 @@ namespace ICSharpCode.SharpDevelop
return ICSharpCode.NRefactory.Utils.TreeTraversal.PreOrder(input, recursion);
}
/// <summary>
/// Creates an array containing a part of the array (similar to string.Substring).
/// </summary>
public static T[] Splice<T>(this T[] array, int startIndex)
{
if (array == null)
throw new ArgumentNullException("array");
return Splice(array, startIndex, array.Length - startIndex);
}
/// <summary>
/// Creates an array containing a part of the array (similar to string.Substring).
/// </summary>
public static T[] Splice<T>(this T[] array, int startIndex, int length)
{
if (array == null)
throw new ArgumentNullException("array");
if (startIndex < 0 || startIndex > array.Length)
throw new ArgumentOutOfRangeException("startIndex", startIndex, "Value must be between 0 and " + array.Length);
if (length < 0 || length > array.Length - startIndex)
throw new ArgumentOutOfRangeException("length", length, "Value must be between 0 and " + (array.Length - startIndex));
T[] result = new T[length];
Array.Copy(array, startIndex, result, 0, length);
return result;
}
public static IEnumerable<T> DistinctBy<T, K>(this IEnumerable<T> input, Func<T, K> keySelector)
{
return input.Distinct(KeyComparer.Create(keySelector));
}
/// <summary>
/// Returns the index of the first element for which <paramref name="predicate"/> returns true.
/// If none of the items in the list fits the <paramref name="predicate"/>, -1 is returned.
/// </summary>
public static int FindIndex<T>(this IList<T> list, Func<T, bool> predicate)
{
for (int i = 0; i < list.Count; i++) {
if (predicate(list[i]))
return i;
}
return -1;
}
/// <summary>
/// Returns the index of the first element for which <paramref name="predicate"/> returns true.
/// If none of the items in the list fits the <paramref name="predicate"/>, -1 is returned.
/// </summary>
public static int FindIndex<T>(this IReadOnlyList<T> list, Func<T, bool> predicate)
{
for (int i = 0; i < list.Count; i++) {
if (predicate(list[i]))
return i;
}
return -1;
}
/// <summary>
/// Adds item to the list if the item is not null.
/// </summary>
public static void AddIfNotNull<T>(this IList<T> list, T itemToAdd) where T : class
{
if (itemToAdd != null)
list.Add(itemToAdd);
}
public static void RemoveAll<T>(this IList<T> list, Predicate<T> condition)
{
if (list == null)
throw new ArgumentNullException("list");
int i = 0;
while (i < list.Count) {
if (condition(list[i]))
list.RemoveAt(i);
else
i++;
}
}
#endregion
#region NRefactory Type System Extensions
/// <summary>
/// Gets the project for which the specified compilation was created.
/// Returns null if the compilation was not created using the SharpDevelop project system.
@ -177,7 +313,7 @@ namespace ICSharpCode.SharpDevelop @@ -177,7 +313,7 @@ namespace ICSharpCode.SharpDevelop
{
if (assembly == null)
throw new ArgumentNullException("assembly");
var snapshot = assembly.Compilation as SharpDevelopSolutionSnapshot;
var snapshot = assembly.Compilation.SolutionSnapshot as SharpDevelopSolutionSnapshot;
if (snapshot == null)
return null;
return snapshot.GetProject(assembly.UnresolvedAssembly as IProjectContent);
@ -215,36 +351,20 @@ namespace ICSharpCode.SharpDevelop @@ -215,36 +351,20 @@ namespace ICSharpCode.SharpDevelop
}
/// <summary>
/// Creates an array containing a part of the array (similar to string.Substring).
/// </summary>
public static T[] Splice<T>(this T[] array, int startIndex)
{
if (array == null)
throw new ArgumentNullException("array");
return Splice(array, startIndex, array.Length - startIndex);
}
/// <summary>
/// Creates an array containing a part of the array (similar to string.Substring).
/// Gets the ambience for the specified compilation.
/// Never returns null.
/// </summary>
public static T[] Splice<T>(this T[] array, int startIndex, int length)
{
if (array == null)
throw new ArgumentNullException("array");
if (startIndex < 0 || startIndex > array.Length)
throw new ArgumentOutOfRangeException("startIndex", startIndex, "Value must be between 0 and " + array.Length);
if (length < 0 || length > array.Length - startIndex)
throw new ArgumentOutOfRangeException("length", length, "Value must be between 0 and " + (array.Length - startIndex));
T[] result = new T[length];
Array.Copy(array, startIndex, result, 0, length);
return result;
}
public static IEnumerable<T> DistinctBy<T, K>(this IEnumerable<T> input, Func<T, K> keySelector)
public static IAmbience GetAmbience(this ICompilation compilation)
{
return input.Distinct(KeyComparer.Create(keySelector));
IProject p = compilation.GetProject();
if (p != null)
return p.GetAmbience();
else
return AmbienceService.GetCurrentAmbience();
}
#endregion
#region WPF SetContent
/// <summary>
/// Sets the Content property of the specified ControlControl to the specified content.
/// If the content is a Windows-Forms control, it is wrapped in a WindowsFormsHost.
@ -325,6 +445,7 @@ namespace ICSharpCode.SharpDevelop @@ -325,6 +445,7 @@ namespace ICSharpCode.SharpDevelop
contentControl.Content = content;
}
}
#endregion
#region System.Drawing <-> WPF conversions
public static System.Drawing.Point ToSystemDrawing(this Point p)
@ -406,6 +527,7 @@ namespace ICSharpCode.SharpDevelop @@ -406,6 +527,7 @@ namespace ICSharpCode.SharpDevelop
}
#endregion
#region String extensions
/// <summary>
/// Removes <param name="stringToRemove" /> from the start of this string.
/// Throws ArgumentException if this string does not start with <param name="stringToRemove" />.
@ -515,6 +637,25 @@ namespace ICSharpCode.SharpDevelop @@ -515,6 +637,25 @@ namespace ICSharpCode.SharpDevelop
}
}
public static int IndexOfAny(this string haystack, IEnumerable<string> needles, int startIndex, out int matchLength)
{
if (haystack == null)
throw new ArgumentNullException("haystack");
if (needles == null)
throw new ArgumentNullException("needles");
int index = -1;
matchLength = 0;
foreach (var needle in needles) {
int i = haystack.IndexOf(needle, startIndex, StringComparison.Ordinal);
if (i != -1 && (index == -1 || index > i)) {
index = i;
matchLength = needle.Length;
}
}
return index;
}
#endregion
/// <summary>
/// Creates a new image for the image source.
/// </summary>
@ -525,55 +666,7 @@ namespace ICSharpCode.SharpDevelop @@ -525,55 +666,7 @@ namespace ICSharpCode.SharpDevelop
return new Image { Source = image.ImageSource };
}
/// <summary>
/// Returns the index of the first element for which <paramref name="predicate"/> returns true.
/// If none of the items in the list fits the <paramref name="predicate"/>, -1 is returned.
/// </summary>
public static int FindIndex<T>(this IList<T> list, Func<T, bool> predicate)
{
for (int i = 0; i < list.Count; i++) {
if (predicate(list[i]))
return i;
}
return -1;
}
/// <summary>
/// Returns the index of the first element for which <paramref name="predicate"/> returns true.
/// If none of the items in the list fits the <paramref name="predicate"/>, -1 is returned.
/// </summary>
public static int FindIndex<T>(this IReadOnlyList<T> list, Func<T, bool> predicate)
{
for (int i = 0; i < list.Count; i++) {
if (predicate(list[i]))
return i;
}
return -1;
}
/// <summary>
/// Adds item to the list if the item is not null.
/// </summary>
public static void AddIfNotNull<T>(this IList<T> list, T itemToAdd) where T : class
{
if (itemToAdd != null)
list.Add(itemToAdd);
}
public static void RemoveWhere<T>(this IList<T> list, Predicate<T> condition)
{
if (list == null)
throw new ArgumentNullException("list");
int i = 0;
while (i < list.Count) {
if (condition(list[i]))
list.RemoveAt(i);
else
i++;
}
}
#region XML extensions
public static XElement FormatXml(this XElement element, int indentationLevel)
{
StringWriter sw = new StringWriter();
@ -641,26 +734,9 @@ namespace ICSharpCode.SharpDevelop @@ -641,26 +734,9 @@ namespace ICSharpCode.SharpDevelop
element.AddFirst(new XText(Environment.NewLine + indentation.ToString()));
return newContent;
}
#endregion
public static int IndexOfAny(this string haystack, IEnumerable<string> needles, int startIndex, out int matchLength)
{
if (haystack == null)
throw new ArgumentNullException("haystack");
if (needles == null)
throw new ArgumentNullException("needles");
int index = -1;
matchLength = 0;
foreach (var needle in needles) {
int i = haystack.IndexOf(needle, startIndex, StringComparison.Ordinal);
if (i != -1 && (index == -1 || index > i)) {
index = i;
matchLength = needle.Length;
}
}
return index;
}
#region Dom, AST, Editor, Document
#region Compatibility extension methods (to reduce merge conflicts SD4->SD5)
public static string GetText(this IDocument document, TextLocation startPos, TextLocation endPos)
{
int startOffset = document.GetOffset(startPos);
@ -672,21 +748,6 @@ namespace ICSharpCode.SharpDevelop @@ -672,21 +748,6 @@ namespace ICSharpCode.SharpDevelop
editor.Select(editor.Document.GetOffset(editor.Caret.Location), 0);
}
/// <summary>
/// Gets the ambience for the specified compilation.
/// Never returns null.
/// </summary>
public static IAmbience GetAmbience(this ICompilation compilation)
{
IProject p = compilation.GetProject();
if (p != null)
return p.GetAmbience();
else
return AmbienceService.GetCurrentAmbience();
}
#endregion
#region Compatibility extension methods (to reduce merge conflicts SD4->SD5)
/// <summary>
/// Obsolete. Use GetOffset() instead.
/// </summary>

Loading…
Cancel
Save