diff --git a/data/resources/image/BitmapResources/BitmapResources.res b/data/resources/image/BitmapResources/BitmapResources.res
index a38078b97e..ffb82aa8ab 100644
--- a/data/resources/image/BitmapResources/BitmapResources.res
+++ b/data/resources/image/BitmapResources/BitmapResources.res
@@ -479,4 +479,7 @@ NAntAddIn.Icons.16x16.RunNAnt = NAntIcons\NAntAddIn.Icons.16x16.RunNA
NAntAddIn.Icons.16x16.RunNAntClean = NAntIcons\NAntAddIn.Icons.16x16.RunNAntClean.png
NAntAddIn.Icons.16x16.StopNAnt = NAntIcons\NAntAddIn.Icons.16x16.StopNAnt.png
+CodeCoverage.Icons.16x16.Pad = CodeCoverageIcons\CodeCoverage.Icons.16x16.Pad.png
+CodeCoverage.Icons.16x16.File = CodeCoverageIcons\CodeCoverage.Icons.16x16.File.png
+CodeCoverage.Icons.16x16.Run = CodeCoverageIcons\CodeCoverage.Icons.16x16.Run.png
diff --git a/data/resources/image/BitmapResources/CodeCoverageIcons/CodeCoverage.Icons.16x16.File.png b/data/resources/image/BitmapResources/CodeCoverageIcons/CodeCoverage.Icons.16x16.File.png
new file mode 100644
index 0000000000..80b12316fc
Binary files /dev/null and b/data/resources/image/BitmapResources/CodeCoverageIcons/CodeCoverage.Icons.16x16.File.png differ
diff --git a/data/resources/image/BitmapResources/CodeCoverageIcons/CodeCoverage.Icons.16x16.Pad.png b/data/resources/image/BitmapResources/CodeCoverageIcons/CodeCoverage.Icons.16x16.Pad.png
new file mode 100644
index 0000000000..5d40a72993
Binary files /dev/null and b/data/resources/image/BitmapResources/CodeCoverageIcons/CodeCoverage.Icons.16x16.Pad.png differ
diff --git a/data/resources/image/BitmapResources/CodeCoverageIcons/CodeCoverage.Icons.16x16.Run.png b/data/resources/image/BitmapResources/CodeCoverageIcons/CodeCoverage.Icons.16x16.Run.png
new file mode 100644
index 0000000000..8701bfb564
Binary files /dev/null and b/data/resources/image/BitmapResources/CodeCoverageIcons/CodeCoverage.Icons.16x16.Run.png differ
diff --git a/src/AddIns/Misc/CodeCoverage/CodeCoverage.sln b/src/AddIns/Misc/CodeCoverage/CodeCoverage.sln
new file mode 100644
index 0000000000..c00d9c5866
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/CodeCoverage.sln
@@ -0,0 +1,68 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# SharpDevelop 2.0.0.960
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCoverage", "Project\CodeCoverage.csproj", "{B7F1A068-01F5-49E7-83EF-05DE281B09FD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCoverage.Tests", "Test\CodeCoverage.Tests.csproj", "{A5C0E8F8-9D04-46ED-91D6-1DEF1575313B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MbUnitPad", "..\MbUnitPad\Project\MbUnitPad.csproj", "{B1CE28A0-04E8-490D-8256-E0C4D52C93C8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.TextEditor", "..\..\..\Libraries\ICSharpCode.TextEditor\Project\ICSharpCode.TextEditor.csproj", "{2D18BE89-D210-49EB-A9DD-2246FBB3DF6D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "nunit.framework.dll", "..\..\..\Libraries\NUnit.Framework\nunit.framework.dll.csproj", "{83DD7E12-A705-4DBA-9D71-09C8973D9382}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinFormsUI", "..\..\..\Libraries\DockPanel_Src\WinFormsUI\WinFormsUI.csproj", "{D3C782BA-178E-4235-A3BA-8C11DEBB6BEE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Core", "..\..\..\Main\Core\Project\ICSharpCode.Core.csproj", "{35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.SharpDevelop", "..\..\..\Main\Base\Project\ICSharpCode.SharpDevelop.csproj", "{2748AD25-9C63-4E12-877B-4DCE96FBED54}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NRefactory", "..\..\..\Libraries\NRefactory\Project\NRefactory.csproj", "{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B7F1A068-01F5-49E7-83EF-05DE281B09FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B7F1A068-01F5-49E7-83EF-05DE281B09FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B7F1A068-01F5-49E7-83EF-05DE281B09FD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B7F1A068-01F5-49E7-83EF-05DE281B09FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A5C0E8F8-9D04-46ED-91D6-1DEF1575313B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A5C0E8F8-9D04-46ED-91D6-1DEF1575313B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A5C0E8F8-9D04-46ED-91D6-1DEF1575313B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A5C0E8F8-9D04-46ED-91D6-1DEF1575313B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B1CE28A0-04E8-490D-8256-E0C4D52C93C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B1CE28A0-04E8-490D-8256-E0C4D52C93C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B1CE28A0-04E8-490D-8256-E0C4D52C93C8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B1CE28A0-04E8-490D-8256-E0C4D52C93C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2D18BE89-D210-49EB-A9DD-2246FBB3DF6D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2D18BE89-D210-49EB-A9DD-2246FBB3DF6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2D18BE89-D210-49EB-A9DD-2246FBB3DF6D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2D18BE89-D210-49EB-A9DD-2246FBB3DF6D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {83DD7E12-A705-4DBA-9D71-09C8973D9382}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {83DD7E12-A705-4DBA-9D71-09C8973D9382}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {83DD7E12-A705-4DBA-9D71-09C8973D9382}.Release|Any CPU.Build.0 = Release|Any CPU
+ {83DD7E12-A705-4DBA-9D71-09C8973D9382}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D3C782BA-178E-4235-A3BA-8C11DEBB6BEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D3C782BA-178E-4235-A3BA-8C11DEBB6BEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D3C782BA-178E-4235-A3BA-8C11DEBB6BEE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D3C782BA-178E-4235-A3BA-8C11DEBB6BEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2748AD25-9C63-4E12-877B-4DCE96FBED54}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2748AD25-9C63-4E12-877B-4DCE96FBED54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2748AD25-9C63-4E12-877B-4DCE96FBED54}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2748AD25-9C63-4E12-877B-4DCE96FBED54}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F6A02431-167E-4347-BC43-65532C31CDB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F6A02431-167E-4347-BC43-65532C31CDB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F6A02431-167E-4347-BC43-65532C31CDB7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F6A02431-167E-4347-BC43-65532C31CDB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/src/AddIns/Misc/CodeCoverage/Project/CodeCoverage.addin b/src/AddIns/Misc/CodeCoverage/Project/CodeCoverage.addin
new file mode 100644
index 0000000000..143630bdfe
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/CodeCoverage.addin
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AddIns/Misc/CodeCoverage/Project/CodeCoverage.csproj b/src/AddIns/Misc/CodeCoverage/Project/CodeCoverage.csproj
new file mode 100644
index 0000000000..39196ba579
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/CodeCoverage.csproj
@@ -0,0 +1,111 @@
+
+
+ Library
+ ICSharpCode.CodeCoverage
+ CodeCoverage
+ Debug
+ AnyCPU
+ {B7F1A068-01F5-49E7-83EF-05DE281B09FD}
+ False
+ False
+ False
+ Auto
+ 4194304
+ AnyCPU
+ 4096
+ 4
+ false
+
+
+ ..\..\..\..\..\AddIns\AddIns\Misc\CodeCoverage\
+ False
+ DEBUG;TRACE
+ true
+ Full
+ True
+
+
+ ..\..\..\..\..\AddIns\AddIns\Misc\CodeCoverage\
+ True
+ TRACE
+ false
+ None
+ False
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+
+
+ {2748AD25-9C63-4E12-877B-4DCE96FBED54}
+ ICSharpCode.SharpDevelop
+ False
+
+
+ {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}
+ ICSharpCode.Core
+ False
+
+
+ {2D18BE89-D210-49EB-A9DD-2246FBB3DF6D}
+ ICSharpCode.TextEditor
+ False
+
+
+ {B1CE28A0-04E8-490D-8256-E0C4D52C93C8}
+ MbUnitPad
+ False
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Configuration/AssemblyInfo.cs b/src/AddIns/Misc/CodeCoverage/Project/Configuration/AssemblyInfo.cs
new file mode 100644
index 0000000000..c833700cbb
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Configuration/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following
+// attributes.
+//
+// change them to the information which is associated with the assembly
+// you compile.
+
+[assembly: AssemblyTitle("CodeCoverage AddIn")]
+[assembly: AssemblyDescription("CodeCoverage AddIn for SharpDevelop 2.0")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("ic#code")]
+[assembly: AssemblyProduct("SharpDevelop")]
+[assembly: AssemblyCopyright("2005-2006 AlphaSierraPapa")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has following format :
+//
+// Major.Minor.Build.Revision
+//
+// You can specify all values by your own or you can build default build and revision
+// numbers with the '*' character (the default):
+
+[assembly: AssemblyVersion("2.0.0.1")]
+
diff --git a/src/AddIns/Misc/CodeCoverage/Project/PostBuildEvent.proj b/src/AddIns/Misc/CodeCoverage/Project/PostBuildEvent.proj
new file mode 100644
index 0000000000..fc90a12e77
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/PostBuildEvent.proj
@@ -0,0 +1,11 @@
+
+
+ $(PrepareForRunDependsOn);MyPostBuildTarget
+
+
+
+
+
+
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Resources/CodeCoverageOptionsPanel.xfrm b/src/AddIns/Misc/CodeCoverage/Project/Resources/CodeCoverageOptionsPanel.xfrm
new file mode 100644
index 0000000000..814f35a34b
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Resources/CodeCoverageOptionsPanel.xfrm
@@ -0,0 +1,142 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Resources/CodeCoverageProjectOptionsPanel.xfrm b/src/AddIns/Misc/CodeCoverage/Project/Resources/CodeCoverageProjectOptionsPanel.xfrm
new file mode 100644
index 0000000000..da111d5b70
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Resources/CodeCoverageProjectOptionsPanel.xfrm
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Resources/CodeCoverageRunnerNotFoundForm.xfrm b/src/AddIns/Misc/CodeCoverage/Project/Resources/CodeCoverageRunnerNotFoundForm.xfrm
new file mode 100644
index 0000000000..236976677f
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Resources/CodeCoverageRunnerNotFoundForm.xfrm
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/AbstractRunTestsWithCodeCoverageCommand.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/AbstractRunTestsWithCodeCoverageCommand.cs
new file mode 100644
index 0000000000..f45c6cab2a
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/AbstractRunTestsWithCodeCoverageCommand.cs
@@ -0,0 +1,287 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.SharpDevelop;
+using ICSharpCode.SharpDevelop.Gui;
+using ICSharpCode.SharpDevelop.Project;
+using System;
+using System.IO;
+using System.Reflection;
+using System.Text;
+
+namespace ICSharpCode.CodeCoverage
+{
+ ///
+ /// Base class that provides an NCover runner to run tests
+ /// with code coverage
+ ///
+ public abstract class AbstractRunTestsWithCodeCoverageCommand : AbstractMenuCommand
+ {
+ static MessageViewCategory category;
+ static NCoverRunner runner;
+
+ public AbstractRunTestsWithCodeCoverageCommand()
+ {
+ if (runner == null) {
+ runner = NCoverRunnerSingleton.Runner;
+ runner.NCoverExited += new NCoverExitEventHandler(NCoverExited);
+ runner.OutputLineReceived += new LineReceivedEventHandler(OutputLineReceived);
+ }
+ }
+
+ public override void Run()
+ {
+ if (IsBuildRunning) {
+ throw new CodeCoverageException();
+ }
+
+ string ncoverFileName = GetNCoverFileName();
+ if (ncoverFileName != null) {
+ SetNCoverRunnerProperties(ncoverFileName);
+ RunNCover();
+ } else {
+ using (CodeCoverageRunnerNotFoundForm form = new CodeCoverageRunnerNotFoundForm()) {
+ form.ShowDialog();
+ }
+ }
+ }
+
+ ///
+ /// Returns the full filename of the assembly being tested.
+ ///
+ ///
+ protected virtual string GetTestAssemblyFileName()
+ {
+ return String.Empty;
+ }
+
+ ///
+ /// Returns the project containing the tests.
+ ///
+ protected virtual IProject GetProject()
+ {
+ return null;
+ }
+
+ bool IsBuildRunning {
+ get {
+ return runner.IsRunning;
+ }
+ }
+
+ ///
+ /// Gets the message view output window.
+ ///
+ MessageViewCategory Category {
+ get {
+ if (category == null) {
+ category = new MessageViewCategory("Code Coverage");
+ CompilerMessageView cmv = (CompilerMessageView)WorkbenchSingleton.Workbench.GetPad(typeof(CompilerMessageView)).PadContent;
+ cmv.AddCategory(category);
+ }
+ return category;
+ }
+ }
+
+ ///
+ /// Writes a line of text to the output window.
+ ///
+ void CategoryWriteLine(string message)
+ {
+ Category.AppendText(String.Concat(message, Environment.NewLine));
+ }
+
+ ///
+ /// Brings output pad to the front.
+ ///
+ void ShowOutputPad()
+ {
+ WorkbenchSingleton.Workbench.GetPad(typeof(CompilerMessageView)).BringPadToFront();
+ }
+
+ bool FileNameExists(string fileName)
+ {
+ return fileName.Length > 0 && File.Exists(fileName);
+ }
+
+ void SetNCoverRunnerProperties(string ncoverFileName)
+ {
+ IProject project = GetProject();
+ string ncoverOutputDirectory = GetNCoverOutputDirectory(project);
+ runner.NCoverFileName = ncoverFileName;
+ runner.ProfiledApplicationCommand = GetMbUnitConsoleFileName();
+ runner.ProfiledApplicationCommandLineArguments = GetMbUnitConsoleCommandLineArguments(ncoverOutputDirectory);
+ runner.WorkingDirectory = Path.GetDirectoryName(GetTestAssemblyFileName());
+ runner.CoverageResultsFileName = Path.Combine(ncoverOutputDirectory, "Coverage.Xml");
+ runner.LogFileName = Path.Combine(ncoverOutputDirectory, "Coverage.log");
+ runner.AssemblyList = GetAssemblyList(project);
+ }
+
+ void RunNCover()
+ {
+ CodeCoverageService.ClearResults();
+
+ Category.ClearText();
+ TaskService.ClearExceptCommentTasks();
+ ShowOutputPad();
+
+ // Remove existing coverage results file.
+ if (File.Exists(runner.CoverageResultsFileName)) {
+ File.Delete(runner.CoverageResultsFileName);
+ }
+
+ // Create NCover output directory.
+ if (!Directory.Exists(Path.GetDirectoryName(runner.CoverageResultsFileName))) {
+ Directory.CreateDirectory(Path.GetDirectoryName(runner.CoverageResultsFileName));
+ }
+
+ CategoryWriteLine(StringParser.Parse("Running NCover..."));
+ CategoryWriteLine(runner.CommandLine);
+
+ runner.Start();
+ }
+
+ ///
+ /// Displays the output from NCover after it has exited.
+ ///
+ /// The event source.
+ /// The NCover exit event arguments.
+ void NCoverExited(object sender, NCoverExitEventArgs e)
+ {
+ System.Diagnostics.Debug.Assert(e.Error.Length == 0);
+
+ string ncoverOutputDirectory = Path.GetDirectoryName(runner.CoverageResultsFileName);
+ string mbunitResultsFileName = Path.Combine(ncoverOutputDirectory, "mbunit.xml");
+ DisplayMbUnitResults(mbunitResultsFileName);
+ DisplayCoverageResults(runner.CoverageResultsFileName);
+
+ if (TaskService.SomethingWentWrong) {
+ ShowErrorList();
+ }
+ }
+
+ void OutputLineReceived(object sender, LineReceivedEventArgs e)
+ {
+ CategoryWriteLine(e.Line);
+ }
+
+ void DisplayCoverageResults(string fileName)
+ {
+ if (!File.Exists(fileName)) {
+ Task task = new Task(String.Empty, String.Concat("No code coverage results file generated: ", fileName), 0, 0, TaskType.Error);
+ WorkbenchSingleton.SafeThreadAsyncCall(typeof(TaskService), "Add", new object[] {task});
+ return;
+ }
+
+ CodeCoverageResults results = new CodeCoverageResults(fileName);
+ WorkbenchSingleton.SafeThreadAsyncCall(typeof(CodeCoverageService), "ShowResults", new object[] {results});
+ }
+
+ void DisplayMbUnitResults(string fileName)
+ {
+ if (!File.Exists(fileName)) {
+ Task task = new Task(String.Empty, String.Concat("No MbUnit results file generated: ", fileName), 0, 0, TaskType.Error);
+ WorkbenchSingleton.SafeThreadAsyncCall(typeof(TaskService), "Add", new object[] {task});
+ return;
+ }
+
+ MbUnitResults results = new MbUnitResults(fileName);
+ foreach (Task task in results.Tasks) {
+ WorkbenchSingleton.SafeThreadAsyncCall(typeof(TaskService), "Add", new object[] {task});
+ }
+ }
+
+ ///
+ /// Returns the full path to the NCover console application if it
+ /// exists.
+ ///
+ string GetNCoverFileName()
+ {
+ string ncoverFileName = CodeCoverageOptions.NCoverFileName;
+ if (FileNameExists(ncoverFileName)) {
+ return ncoverFileName;
+ } else {
+ ncoverFileName = GetDefaultNCoverFileName();
+ if (FileNameExists(ncoverFileName)) {
+ return ncoverFileName;
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// Returns the default full path to the NCover console application.
+ ///
+ ///
+ string GetDefaultNCoverFileName()
+ {
+ string programFilesPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
+ return Path.Combine(programFilesPath, @"NCover\NCover.Console.exe");
+ }
+
+ void ShowErrorList()
+ {
+ PadDescriptor padDescriptor = WorkbenchSingleton.Workbench.GetPad(typeof(ErrorListPad));
+ if (padDescriptor != null) {
+ WorkbenchSingleton.SafeThreadAsyncCall(padDescriptor, "BringPadToFront");
+ }
+ }
+
+ ///
+ /// Reads the list of assemblies to be profiled from the project's
+ /// NCover settings.
+ ///
+ string GetAssemblyList(IProject project)
+ {
+ if (project == null) {
+ return String.Empty;
+ }
+
+ string ncoverSettingsFileName = NCoverSettings.GetFileName(project);
+ if (File.Exists(ncoverSettingsFileName)) {
+ NCoverSettings settings = new NCoverSettings(ncoverSettingsFileName);
+ return settings.AssemblyList;
+ }
+ return String.Empty;
+ }
+
+ string GetNCoverOutputDirectory(IProject project)
+ {
+ return Path.Combine(project.Directory, "NCover");
+ }
+
+ ///
+ /// Gets the assembly folder where this add-in was loaded from.
+ ///
+ /// The assembly folder where this add-in was loaded.
+ string GetAssemblyFolder()
+ {
+ Assembly assembly = GetType().Assembly;
+ string assemblyFilename = assembly.CodeBase.Replace("file:///", String.Empty);
+ return Path.GetDirectoryName(assemblyFilename);
+ }
+
+ string GetMbUnitConsoleFileName()
+ {
+ return Path.GetFullPath(Path.Combine(GetAssemblyFolder(),
+ @"..\..\..\..\bin\Tools\MbUnit\MbUnit.Cons.exe"));
+ }
+
+ string GetMbUnitConsoleCommandLineArguments(string reportFolder)
+ {
+ StringBuilder commandLine = new StringBuilder();
+
+ commandLine.Append("/report-name-format:mbunit ");
+ commandLine.Append("/report-type:Xml ");
+ commandLine.AppendFormat("/report-folder:\"{0}\" ", reportFolder);
+ commandLine.AppendFormat("\"{0}\"", GetTestAssemblyFileName());
+
+ return commandLine.ToString();
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageClassTreeNode.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageClassTreeNode.cs
new file mode 100644
index 0000000000..970c37383e
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageClassTreeNode.cs
@@ -0,0 +1,32 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using System;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoverageClassTreeNode : CodeCoverageTreeNode
+ {
+ public CodeCoverageClassTreeNode(string name) : base(name)
+ {
+ ImageIndex = ClassBrowserIconService.ClassIndex;
+ SelectedImageIndex = ImageIndex;
+ }
+
+ public override void ActivateItem()
+ {
+ if (Nodes.Count > 0) {
+ CodeCoverageMethodTreeNode methodNode = (CodeCoverageMethodTreeNode)Nodes[0];
+ if (methodNode.Method.SequencePoints.Count > 0) {
+ FileService.OpenFile(methodNode.Method.SequencePoints[0].Document);
+ }
+ }
+ }
+
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageControl.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageControl.cs
new file mode 100644
index 0000000000..de612446d8
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageControl.cs
@@ -0,0 +1,158 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoverageControl : UserControl
+ {
+ CodeCoverageTreeView treeView;
+ ListView listView;
+ SplitContainer splitContainer;
+ ColumnHeader visitCountColumnHeader;
+ ColumnHeader startLineColumnHeader;
+ ColumnHeader endLineColumnHeader;
+ ColumnHeader startColumnColumnHeader;
+ ColumnHeader endColumnColumnHeader;
+ ToolStrip toolStrip;
+
+ public CodeCoverageControl()
+ {
+ // TreeView
+ treeView = new CodeCoverageTreeView();
+ treeView.Dock = DockStyle.Fill;
+ treeView.ImageList = ClassBrowserIconService.ImageList;
+ treeView.AfterSelect += CodeCoverageTreeViewAfterSelect;
+
+ // ListView
+ listView = new ListView();
+ listView.View = View.Details;
+ listView.Dock = DockStyle.Fill;
+ listView.FullRowSelect = true;
+ listView.HideSelection = false;
+ listView.ItemActivate += ListViewItemActivate;
+
+ visitCountColumnHeader = new ColumnHeader();
+ visitCountColumnHeader.Text = "Visit Count";
+ visitCountColumnHeader.Width = 80;
+
+ startLineColumnHeader = new ColumnHeader();
+ startLineColumnHeader.Text = "Line";
+ startLineColumnHeader.Width = 80;
+
+ startColumnColumnHeader = new ColumnHeader();
+ startColumnColumnHeader.Text = "Column";
+ startColumnColumnHeader.Width = 80;
+
+ endLineColumnHeader = new ColumnHeader();
+ endLineColumnHeader.Text = "End Line";
+ endLineColumnHeader.Width = 80;
+
+ endColumnColumnHeader = new ColumnHeader();
+ endColumnColumnHeader.Text = "End Column";
+ endColumnColumnHeader.Width = 80;
+
+ listView.Columns.AddRange(new ColumnHeader[] {visitCountColumnHeader,
+ startLineColumnHeader,
+ startColumnColumnHeader,
+ endLineColumnHeader,
+ endColumnColumnHeader});
+
+ // SplitContainer.
+ splitContainer = new SplitContainer();
+ splitContainer.SplitterWidth = 2;
+ splitContainer.Dock = DockStyle.Fill;
+ splitContainer.Panel1.Controls.Add(treeView);
+ splitContainer.Panel2.Controls.Add(listView);
+
+ Controls.Add(splitContainer);
+
+ // Toolstrip
+ toolStrip = ToolbarService.CreateToolStrip(this, "/SharpDevelop/Pads/CodeCoveragePad/Toolbar");
+ toolStrip.GripStyle = ToolStripGripStyle.Hidden;
+ Controls.Add(toolStrip);
+ }
+
+ public void UpdateToolbar()
+ {
+ ToolbarService.UpdateToolbar(toolStrip);
+ toolStrip.Refresh();
+ }
+
+ public void AddModules(List modules)
+ {
+ LoggingService.Debug("AddModules...");
+ treeView.AddModules(modules);
+ }
+
+ public void Clear()
+ {
+ treeView.Clear();
+ listView.Items.Clear();
+ }
+
+ void CodeCoverageTreeViewAfterSelect(object sender, TreeViewEventArgs e)
+ {
+ UpdateListView((CodeCoverageTreeNode)e.Node);
+ }
+
+ void UpdateListView(CodeCoverageTreeNode node)
+ {
+ listView.BeginUpdate();
+ try {
+ listView.Items.Clear();
+ if (node is CodeCoverageClassTreeNode) {
+ AddClass((CodeCoverageClassTreeNode)node);
+ } else if (node is CodeCoverageMethodTreeNode) {
+ AddMethod((CodeCoverageMethodTreeNode)node);
+ }
+ } finally {
+ listView.EndUpdate();
+ }
+ }
+
+ void AddClass(CodeCoverageClassTreeNode node)
+ {
+ foreach (CodeCoverageMethodTreeNode method in node.Nodes) {
+ AddMethod(method);
+ }
+ }
+
+ void AddMethod(CodeCoverageMethodTreeNode node)
+ {
+ foreach (CodeCoverageSequencePoint sequencePoint in node.Method.SequencePoints) {
+ AddSequencePoint(sequencePoint);
+ }
+ }
+
+ void AddSequencePoint(CodeCoverageSequencePoint sequencePoint)
+ {
+ ListViewItem item = new ListViewItem(sequencePoint.VisitCount.ToString());
+ item.SubItems.Add(sequencePoint.Line.ToString());
+ item.SubItems.Add(sequencePoint.Column.ToString());
+ item.SubItems.Add(sequencePoint.EndLine.ToString());
+ item.SubItems.Add(sequencePoint.EndColumn.ToString());
+ item.Tag = sequencePoint;
+
+ listView.Items.Add(item);
+ }
+
+ void ListViewItemActivate(object sender, EventArgs e)
+ {
+ if (listView.SelectedItems.Count > 0) {
+ CodeCoverageSequencePoint sequencePoint = (CodeCoverageSequencePoint)listView.SelectedItems[0].Tag;
+ if (sequencePoint.Document.Length > 0) {
+ FileService.JumpToFilePosition(sequencePoint.Document, sequencePoint.Line - 1, sequencePoint.Column - 1);
+ }
+ }
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageDisplayItem.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageDisplayItem.cs
new file mode 100644
index 0000000000..51b1a597f4
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageDisplayItem.cs
@@ -0,0 +1,85 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Drawing;
+
+namespace ICSharpCode.CodeCoverage
+{
+ ///
+ /// Represents a code coverage display item that can have its colour customised
+ /// (e.g. Visited code and Not visited code.
+ ///
+ public class CodeCoverageDisplayItem
+ {
+ string item = String.Empty;
+ string itemBackColorPropertyName = String.Empty;
+ string itemForeColorPropertyName = String.Empty;
+ Color backColor;
+ Color foreColor;
+ bool changed;
+
+ public CodeCoverageDisplayItem(string item, string itemBackColorPropertyName, Color backColor, string itemForeColorPropertyName, Color foreColor)
+ {
+ this.item = item;
+ this.backColor = backColor;
+ this.foreColor = foreColor;
+ this.itemBackColorPropertyName = itemBackColorPropertyName;
+ this.itemForeColorPropertyName = itemForeColorPropertyName;
+ }
+
+ ///
+ /// Gets whether any of the colours has changed from their origina values.
+ ///
+ public bool HasChanged {
+ get {
+ return changed;
+ }
+ }
+
+ public override string ToString()
+ {
+ return item;
+ }
+
+ public string BackColorPropertyName {
+ get {
+ return itemBackColorPropertyName;
+ }
+ }
+
+ public Color BackColor {
+ get {
+ return backColor;
+ }
+ set {
+ if (backColor != value) {
+ backColor = value;
+ changed = true;
+ }
+ }
+ }
+
+ public string ForeColorPropertyName {
+ get {
+ return itemForeColorPropertyName;
+ }
+ }
+
+ public Color ForeColor {
+ get {
+ return foreColor;
+ }
+ set {
+ if (foreColor != null) {
+ foreColor = value;
+ changed = true;
+ }
+ }
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageException.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageException.cs
new file mode 100644
index 0000000000..76a20ad11b
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageException.cs
@@ -0,0 +1,27 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+
+namespace ICSharpCode.CodeCoverage
+{
+ ///
+ /// The exception that is thrown when a non-fatal
+ /// error occurs in the code coverage add-in.
+ ///
+ public class CodeCoverageException : ApplicationException
+ {
+ public CodeCoverageException()
+ {
+ }
+
+ public CodeCoverageException(string message)
+ : base(message)
+ {
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageHighlighter.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageHighlighter.cs
new file mode 100644
index 0000000000..02ac80b2a6
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageHighlighter.cs
@@ -0,0 +1,107 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.TextEditor.Document;
+using System;
+using System.Collections.Generic;
+
+namespace ICSharpCode.CodeCoverage
+{
+ ///
+ /// Highlights the covered and not covered code in the text editor.
+ ///
+ public class CodeCoverageHighlighter
+ {
+ public CodeCoverageHighlighter()
+ {
+ }
+
+ ///
+ /// Adds text markers for the code coverage sequence points.
+ ///
+ /// The sequence points are added to the marker strategy even
+ /// if they are not all for the same document.
+ public void AddMarkers(MarkerStrategy markerStrategy, List sequencePoints)
+ {
+ foreach (CodeCoverageSequencePoint sequencePoint in sequencePoints) {
+ AddMarker(markerStrategy, sequencePoint);
+ }
+ }
+
+ public void AddMarker(MarkerStrategy markerStrategy, CodeCoverageSequencePoint sequencePoint)
+ {
+ if (!IsValidSequencePoint(markerStrategy.Document, sequencePoint)) {
+ return;
+ }
+
+ if (sequencePoint.EndLine == sequencePoint.Line) {
+ LineSegment lineSegment = markerStrategy.Document.GetLineSegment(sequencePoint.Line - 1);
+ markerStrategy.AddMarker(new CodeCoverageTextMarker(lineSegment.Offset + sequencePoint.Column, sequencePoint));
+ } else {
+ // Sequence point spread across lines.
+ for (int line = sequencePoint.Line; line <= sequencePoint.EndLine; ++line) {
+ LineSegment lineSegment = markerStrategy.Document.GetLineSegment(line - 1);
+ if (line == sequencePoint.Line) {
+ // First line.
+ markerStrategy.AddMarker(new CodeCoverageTextMarker(lineSegment.Offset + sequencePoint.Column, lineSegment.Length - (lineSegment.DelimiterLength - 1) - sequencePoint.Column, sequencePoint));
+ } else if (line == sequencePoint.EndLine) {
+ // Last line.
+ markerStrategy.AddMarker(new CodeCoverageTextMarker(lineSegment.Offset, sequencePoint.EndColumn - 1, sequencePoint));
+ } else {
+ markerStrategy.AddMarker(new CodeCoverageTextMarker(lineSegment.Offset, lineSegment.Length - (lineSegment.DelimiterLength - 1), sequencePoint));
+ }
+ }
+ }
+ }
+
+ ///
+ /// Removes all CodeCoverageMarkers from the marker strategy.
+ ///
+ public void RemoveMarkers(MarkerStrategy markerStrategy)
+ {
+ markerStrategy.RemoveAll(IsCodeCoverageTextMarkerMatch);
+ }
+
+ bool IsCodeCoverageTextMarkerMatch(TextMarker marker)
+ {
+ if (marker is CodeCoverageTextMarker) {
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Checks whether the sequence point can be added to the document.
+ ///
+ ///
+ /// Checks for invalid start lines, start columns, end columns and end
+ /// lines that cannot fit in the document.
+ bool IsValidSequencePoint(IDocument document, CodeCoverageSequencePoint sequencePoint)
+ {
+ if (sequencePoint.Line <= 0 || sequencePoint.EndLine <= 0 || sequencePoint.Column <= 0 || sequencePoint.EndColumn <= 0) {
+ return false;
+ } else if (sequencePoint.Line > document.TotalNumberOfLines) {
+ return false;
+ } else if (sequencePoint.EndLine > document.TotalNumberOfLines) {
+ return false;
+ } else if (sequencePoint.Line == sequencePoint.EndLine && sequencePoint.Column > sequencePoint.EndColumn) {
+ return false;
+ } else {
+ // Check the columns exist on the line.
+ LineSegment lineSegment = document.GetLineSegment(sequencePoint.Line - 1);
+ if (sequencePoint.Column > lineSegment.Length) {
+ return false;
+ }
+ LineSegment endLineSegment = document.GetLineSegment(sequencePoint.EndLine - 1);
+ if (sequencePoint.EndColumn > endLineSegment.Length + 1) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageMethod.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageMethod.cs
new file mode 100644
index 0000000000..ca9542634e
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageMethod.cs
@@ -0,0 +1,104 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using System;
+using System.Collections.Generic;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoverageMethod
+ {
+ string name = String.Empty;
+ string className = String.Empty;
+ string fullClassName = String.Empty;
+ string classNamespace = String.Empty;
+ List sequencePoints = new List();
+
+ public CodeCoverageMethod(string name, string className)
+ {
+ this.name = name;
+ this.fullClassName = className;
+
+ int index = fullClassName.LastIndexOf('.');
+ this.classNamespace = fullClassName.Substring(0, index);
+
+ index = fullClassName.LastIndexOf('.');
+ if (index > 0) {
+ this.className = fullClassName.Substring(index + 1);
+ } else {
+ this.className = fullClassName;
+ }
+ }
+
+ public string Name {
+ get {
+ return name;
+ }
+ }
+
+ public string ClassName {
+ get {
+ return className;
+ }
+ }
+
+ public string FullClassName {
+ get {
+ return fullClassName;
+ }
+ }
+
+ public string ClassNamespace {
+ get {
+ return classNamespace;
+ }
+ }
+
+ public List SequencePoints {
+ get {
+ return sequencePoints;
+ }
+ }
+
+ public int VisitedSequencePointsCount {
+ get {
+ int count = 0;
+ foreach (CodeCoverageSequencePoint sequencePoint in sequencePoints) {
+ if (sequencePoint.VisitCount > 0) {
+ count++;
+ }
+ }
+ return count;
+ }
+ }
+
+ public int NotVisitedSequencePointsCount {
+ get {
+ int count = 0;
+ foreach (CodeCoverageSequencePoint sequencePoint in sequencePoints) {
+ if (sequencePoint.VisitCount == 0) {
+ count++;
+ }
+ }
+ return count;
+ }
+ }
+
+ public List GetSequencePoints(string fileName)
+ {
+ List matchedSequencePoints = new List();
+ foreach (CodeCoverageSequencePoint sequencePoint in sequencePoints) {
+ if (FileUtility.IsEqualFileName(fileName, sequencePoint.Document)) {
+ matchedSequencePoints.Add(sequencePoint);
+ }
+ }
+ return matchedSequencePoints;
+ }
+
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageMethodTreeNode.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageMethodTreeNode.cs
new file mode 100644
index 0000000000..14f1fe8bd4
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageMethodTreeNode.cs
@@ -0,0 +1,54 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.SharpDevelop.Gui;
+using System;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoverageMethodTreeNode : CodeCoverageTreeNode
+ {
+ CodeCoverageMethod method;
+
+ public CodeCoverageMethodTreeNode(CodeCoverageMethod method) : base(method.Name, method.VisitedSequencePointsCount, method.NotVisitedSequencePointsCount)
+ {
+ ImageIndex = ClassBrowserIconService.MethodIndex;
+ SelectedImageIndex = ImageIndex;
+ this.method = method;
+ }
+
+ public CodeCoverageMethod Method {
+ get {
+ return method;
+ }
+ }
+
+ public override void ActivateItem()
+ {
+ if (method != null && method.SequencePoints.Count > 0) {
+ CodeCoverageSequencePoint firstSequencePoint = method.SequencePoints[0];
+ int line = firstSequencePoint.Line;
+ int column = firstSequencePoint.Column;
+
+ for (int i = 1; i < method.SequencePoints.Count; ++i) {
+ CodeCoverageSequencePoint sequencePoint = method.SequencePoints[0];
+ if (line > sequencePoint.Line) {
+ line = sequencePoint.Line;
+ column = sequencePoint.Column;
+ }
+ }
+
+ FileService.JumpToFilePosition(firstSequencePoint.Document, line - 1, column - 1);
+
+ } else if (Parent != null) {
+ ((ExtTreeNode)Parent).ActivateItem();
+ }
+ }
+
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageModule.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageModule.cs
new file mode 100644
index 0000000000..d153547978
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageModule.cs
@@ -0,0 +1,64 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Collections.Generic;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoverageModule
+ {
+ string name = String.Empty;
+ List methods = new List();
+
+ public CodeCoverageModule(string name)
+ {
+ this.name = name;
+ }
+
+ public string Name {
+ get {
+ return name;
+ }
+ }
+
+ public List Methods {
+ get {
+ return methods;
+ }
+ }
+
+ public int VisitedSequencePointsCount {
+ get {
+ int count = 0;
+ foreach (CodeCoverageMethod method in methods) {
+ count += method.VisitedSequencePointsCount;
+ }
+ return count;
+ }
+ }
+
+ public int NotVisitedSequencePointsCount {
+ get {
+ int count = 0;
+ foreach (CodeCoverageMethod method in methods) {
+ count += method.NotVisitedSequencePointsCount;
+ }
+ return count;
+ }
+ }
+
+ public List GetSequencePoints(string fileName)
+ {
+ List sequencePoints = new List();
+ foreach (CodeCoverageMethod method in methods) {
+ sequencePoints.AddRange(method.GetSequencePoints(fileName));
+ }
+ return sequencePoints;
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageModuleTreeNode.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageModuleTreeNode.cs
new file mode 100644
index 0000000000..5f5d8550ed
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageModuleTreeNode.cs
@@ -0,0 +1,126 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.SharpDevelop.Gui;
+using System.Collections.Generic;
+using System.Windows.Forms;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoverageModuleTreeNode : CodeCoverageTreeNode
+ {
+ public CodeCoverageModuleTreeNode(CodeCoverageModule module) : base(module.Name, module.VisitedSequencePointsCount, module.NotVisitedSequencePointsCount)
+ {
+ ImageIndex = 2;
+ SelectedImageIndex = ImageIndex;
+
+ foreach (CodeCoverageMethod method in module.Methods) {
+ AddMethod(method);
+ }
+
+ // Update percentage totals for namespace nodes.
+ UpdateNamespacePercentages(Nodes);
+ }
+
+ void AddMethod(CodeCoverageMethod method)
+ {
+ ExtTreeNode parentNode = GetParentNamespaceNode(method.ClassNamespace);
+
+ // Add class node.
+ ExtTreeNode classNode = FindNode(parentNode.Nodes, method.ClassName);
+ if (classNode == null) {
+ classNode = new CodeCoverageClassTreeNode(method.ClassName);
+ classNode.AddTo(parentNode);
+ }
+
+ // Add method node.
+ CodeCoverageMethodTreeNode methodNode = new CodeCoverageMethodTreeNode(method);
+ methodNode.AddTo(classNode);
+ }
+
+ ExtTreeNode GetParentNamespaceNode(string classNamespace)
+ {
+ string[] treePath = classNamespace.Split('.');
+
+ ExtTreeNode node = this;
+ ExtTreeNode currentNode = node;
+
+ foreach (string path in treePath) {
+ if (currentNode != null) {
+ currentNode = FindNode(currentNode.Nodes, path);
+ }
+
+ if (currentNode == null) {
+ CodeCoverageNamespaceTreeNode newNode = new CodeCoverageNamespaceTreeNode(path);
+ newNode.AddTo(node);
+ node = newNode;
+ } else {
+ node = currentNode;
+ }
+ }
+
+ return node;
+ }
+
+ ExtTreeNode FindNode(TreeNodeCollection nodes, string name)
+ {
+ foreach (ExtTreeNode node in nodes) {
+ if (node.Text == name) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ void UpdateNamespacePercentages(TreeNodeCollection nodes)
+ {
+ foreach (ExtTreeNode node in nodes) {
+ CodeCoverageNamespaceTreeNode namespaceNode = node as CodeCoverageNamespaceTreeNode;
+ if (namespaceNode != null) {
+ SumVisits(namespaceNode);
+ }
+ }
+ }
+
+ void SumVisits(CodeCoverageNamespaceTreeNode parentNode)
+ {
+ int visitedCount = 0;
+ int notVisitedCount = 0;
+
+ foreach (CodeCoverageTreeNode node in parentNode.Nodes) {
+ CodeCoverageNamespaceTreeNode namespaceNode = node as CodeCoverageNamespaceTreeNode;
+ CodeCoverageClassTreeNode classNode = node as CodeCoverageClassTreeNode;
+ if (namespaceNode != null) {
+ SumVisits(namespaceNode);
+ } else if (classNode != null) {
+ SumVisits(classNode);
+ }
+
+ visitedCount += node.VisitedCount;
+ notVisitedCount += node.NotVisitedCount;
+ }
+
+ parentNode.VisitedCount = visitedCount;
+ parentNode.NotVisitedCount = notVisitedCount;
+ }
+
+ void SumVisits(CodeCoverageClassTreeNode parentNode)
+ {
+ int visitedCount = 0;
+ int notVisitedCount = 0;
+
+ foreach (CodeCoverageTreeNode node in parentNode.Nodes) {
+ visitedCount += node.VisitedCount;
+ notVisitedCount += node.NotVisitedCount;
+ }
+
+ parentNode.VisitedCount = visitedCount;
+ parentNode.NotVisitedCount = notVisitedCount;
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageNamespaceTreeNode.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageNamespaceTreeNode.cs
new file mode 100644
index 0000000000..4a387cf87e
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageNamespaceTreeNode.cs
@@ -0,0 +1,21 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using System;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoverageNamespaceTreeNode : CodeCoverageTreeNode
+ {
+ public CodeCoverageNamespaceTreeNode(string name) : base(name)
+ {
+ ImageIndex = ClassBrowserIconService.NamespaceIndex;
+ SelectedImageIndex = ImageIndex;
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageOptions.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageOptions.cs
new file mode 100644
index 0000000000..256812c817
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageOptions.cs
@@ -0,0 +1,123 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using System;
+using System.Drawing;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoverageOptions
+ {
+ public static readonly string OptionsProperty = "CodeCoverage.Options";
+
+ #region Property names
+ public static readonly string VisitedColorProperty = "VisitedColor";
+ public static readonly string VisitedForeColorProperty = "VisitedForeColor";
+ public static readonly string NotVisitedColorProperty = "NotVisitedColor";
+ public static readonly string NotVisitedForeColorProperty = "NotVisitedForeColor";
+ public static readonly string NCoverFileNameProperty = "NCoverFileName";
+ public static readonly string CodeCoverageHighlightedProperty = "CodeCoverageHighlighted";
+ #endregion
+
+ static Properties properties;
+
+ static CodeCoverageOptions()
+ {
+ properties = PropertyService.Get(OptionsProperty, new Properties());
+ }
+
+ public static Properties Properties {
+ get {
+ return properties;
+ }
+ }
+
+ ///
+ /// The full path to the NCover console executable.
+ ///
+ public static string NCoverFileName {
+ get {
+ return Properties.Get(NCoverFileNameProperty, String.Empty);
+ }
+ set {
+ Properties.Set(NCoverFileNameProperty, value);
+ }
+ }
+
+ ///
+ /// Enables/disables code coverage highlighting.
+ ///
+ public static bool CodeCoverageHighlighted {
+ get {
+ return Properties.Get(CodeCoverageHighlightedProperty, false);
+ }
+ set {
+ Properties.Set(CodeCoverageHighlightedProperty, value);
+ }
+ }
+
+ ///
+ /// Gets the colour that will be used when highlighting visited code.
+ ///
+ public static Color VisitedColor
+ {
+ get {
+ return Properties.Get(VisitedColorProperty, Color.Lime);
+ }
+
+ set {
+ Properties.Set(VisitedColorProperty, value);
+ }
+ }
+
+ ///
+ /// Gets the foreground colour that will be used when highlighting
+ /// visited code.
+ ///
+ public static Color VisitedForeColor
+ {
+ get {
+ return Properties.Get(VisitedForeColorProperty, Color.Black);
+ }
+
+ set {
+ Properties.Set(VisitedForeColorProperty, value);
+ }
+ }
+
+ ///
+ /// Gets the colour that will be used when highlighting code that has not
+ /// been visited.
+ ///
+ public static Color NotVisitedColor
+ {
+ get {
+ return Properties.Get(NotVisitedColorProperty, Color.Red);
+ }
+
+ set {
+ Properties.Set(NotVisitedColorProperty, value);
+ }
+ }
+
+ ///
+ /// Gets the foreground colour that will be used when highlighting
+ /// code that has not been visited.
+ ///
+ public static Color NotVisitedForeColor
+ {
+ get {
+ return Properties.Get(NotVisitedForeColorProperty, Color.White);
+ }
+
+ set {
+ Properties.Set(NotVisitedForeColorProperty, value);
+ }
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageOptionsPanel.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageOptionsPanel.cs
new file mode 100644
index 0000000000..eccefc3c1d
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageOptionsPanel.cs
@@ -0,0 +1,137 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.SharpDevelop;
+using ICSharpCode.SharpDevelop.Gui;
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoverageOptionsPanel : AbstractOptionPanel
+ {
+ static readonly string foregroundCustomColourButtonName = "foregroundCustomColourButton";
+ static readonly string backgroundCustomColourButtonName = "backgroundCustomColourButton";
+ static readonly string foregroundColourComboBoxName = "foregroundColorPickerComboBox";
+ static readonly string backgroundColourComboBoxName = "backgroundColorPickerComboBox";
+ static readonly string displayItemsListBoxName = "displayItemsListBox";
+ static readonly string sampleTextLabelName = "sampleTextLabel";
+ static readonly string browseButtonName = "browseButton";
+ static readonly string commandTextBoxName = "commandTextBox";
+
+ ColorPickerComboBox foregroundColorPickerComboBox;
+ ColorPickerComboBox backgroundColorPickerComboBox;
+ ListBox displayItemsListBox;
+ Label sampleTextLabel;
+ TextBox commandTextBox;
+
+ public override void LoadPanelContents()
+ {
+ SetupFromXmlStream(this.GetType().Assembly.GetManifestResourceStream("ICSharpCode.CodeCoverage.Resources.CodeCoverageOptionsPanel.xfrm"));
+
+ ControlDictionary[foregroundCustomColourButtonName].Click += new EventHandler(ForegroundCustomColourButtonClick);
+ ControlDictionary[backgroundCustomColourButtonName].Click += new EventHandler(BackgroundCustomColourButtonClick);
+ ControlDictionary[browseButtonName].Click += new EventHandler(BrowseButtonClick);
+
+ foregroundColorPickerComboBox = (ColorPickerComboBox)ControlDictionary[foregroundColourComboBoxName];
+ foregroundColorPickerComboBox.SelectedIndexChanged += ForegroundColorPickerComboBoxSelectedIndexChanged;
+
+ backgroundColorPickerComboBox = (ColorPickerComboBox)ControlDictionary[backgroundColourComboBoxName];
+ backgroundColorPickerComboBox.SelectedIndexChanged += BackgroundColorPickerComboBoxSelectedIndexChanged;
+
+ sampleTextLabel = (Label)ControlDictionary[sampleTextLabelName];
+
+ commandTextBox = (TextBox)ControlDictionary[commandTextBoxName];
+ commandTextBox.Text = CodeCoverageOptions.NCoverFileName;
+
+ displayItemsListBox = (ListBox)ControlDictionary[displayItemsListBoxName];
+ displayItemsListBox.Items.Add(new CodeCoverageDisplayItem("Code Covered", CodeCoverageOptions.VisitedColorProperty, CodeCoverageOptions.VisitedColor, CodeCoverageOptions.VisitedForeColorProperty, CodeCoverageOptions.VisitedForeColor));
+ displayItemsListBox.Items.Add(new CodeCoverageDisplayItem("Code Not Covered", CodeCoverageOptions.NotVisitedColorProperty, CodeCoverageOptions.NotVisitedColor, CodeCoverageOptions.NotVisitedForeColorProperty, CodeCoverageOptions.NotVisitedForeColor));
+ displayItemsListBox.SelectedIndexChanged += DisplayItemsListBoxSelectedIndexChanged;
+ displayItemsListBox.SelectedIndex = 0;
+ }
+
+ public override bool StorePanelContents()
+ {
+ bool codeCoverageColorsChanged = false;
+
+ foreach (CodeCoverageDisplayItem item in displayItemsListBox.Items) {
+ CodeCoverageOptions.Properties.Set(item.ForeColorPropertyName, item.ForeColor);
+ CodeCoverageOptions.Properties.Set(item.BackColorPropertyName, item.BackColor);
+ if (item.HasChanged) {
+ codeCoverageColorsChanged = true;
+ }
+ }
+
+ if (codeCoverageColorsChanged) {
+ CodeCoverageService.RefreshCodeCoverageHighlights();
+ }
+
+ CodeCoverageOptions.NCoverFileName = commandTextBox.Text;
+
+ return true;
+ }
+
+ void ForegroundCustomColourButtonClick(object sender, EventArgs e)
+ {
+ SelectCustomColour(foregroundColorPickerComboBox);
+ }
+
+ void BackgroundCustomColourButtonClick(object sender, EventArgs e)
+ {
+ SelectCustomColour(backgroundColorPickerComboBox);
+ }
+
+ void SelectCustomColour(ColorPickerComboBox comboBox)
+ {
+ using (ColorDialog colorDialog = new ColorDialog()) {
+ colorDialog.FullOpen = true;
+ if (colorDialog.ShowDialog() == DialogResult.OK) {
+ comboBox.SelectedColor = colorDialog.Color;
+ }
+ }
+ }
+
+ void DisplayItemsListBoxSelectedIndexChanged(object sender, EventArgs e)
+ {
+ CodeCoverageDisplayItem item = (CodeCoverageDisplayItem)displayItemsListBox.SelectedItem;
+ sampleTextLabel.BackColor = item.BackColor;
+ sampleTextLabel.ForeColor = item.ForeColor;
+ foregroundColorPickerComboBox.SelectedColor = item.ForeColor;
+ backgroundColorPickerComboBox.SelectedColor = item.BackColor;
+ }
+
+ void ForegroundColorPickerComboBoxSelectedIndexChanged(object sender, EventArgs e)
+ {
+ CodeCoverageDisplayItem item = (CodeCoverageDisplayItem)displayItemsListBox.SelectedItem;
+ sampleTextLabel.ForeColor = foregroundColorPickerComboBox.SelectedColor;
+ item.ForeColor = foregroundColorPickerComboBox.SelectedColor;
+ }
+
+ void BackgroundColorPickerComboBoxSelectedIndexChanged(object sender, EventArgs e)
+ {
+ CodeCoverageDisplayItem item = (CodeCoverageDisplayItem)displayItemsListBox.SelectedItem;
+ sampleTextLabel.BackColor = backgroundColorPickerComboBox.SelectedColor;
+ item.BackColor = backgroundColorPickerComboBox.SelectedColor;
+ }
+
+ void BrowseButtonClick(object sender, EventArgs e)
+ {
+ using (OpenFileDialog openFileDialog = new OpenFileDialog()) {
+ openFileDialog.CheckFileExists = true;
+ openFileDialog.Filter = StringParser.Parse("${res:SharpDevelop.FileFilter.ExecutableFiles}|*.exe|${res:SharpDevelop.FileFilter.AllFiles}|*.*");
+ if (openFileDialog.ShowDialog() == DialogResult.OK) {
+ ControlDictionary[commandTextBoxName].Text = openFileDialog.FileName;
+ }
+ }
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoveragePad.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoveragePad.cs
new file mode 100644
index 0000000000..81390de988
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoveragePad.cs
@@ -0,0 +1,89 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.SharpDevelop.Project;
+using ICSharpCode.SharpDevelop.Gui;
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoveragePad : AbstractPadContent
+ {
+ static CodeCoveragePad instance;
+ bool disposed;
+ CodeCoverageControl codeCoverageControl;
+
+ public CodeCoveragePad()
+ {
+ instance = this;
+
+ codeCoverageControl = new CodeCoverageControl();
+ if (CodeCoverageService.Results != null) {
+ codeCoverageControl.AddModules(CodeCoverageService.Results.Modules);
+ }
+ codeCoverageControl.UpdateToolbar();
+
+ ProjectService.SolutionClosed += SolutionClosed;
+ ProjectService.SolutionLoaded += SolutionLoaded;
+ }
+
+ public static CodeCoveragePad Instance {
+ get {
+ return instance;
+ }
+ }
+
+ public override Control Control {
+ get {
+ return codeCoverageControl;
+ }
+ }
+
+ ///
+ /// Cleans up all used resources
+ ///
+ public override void Dispose()
+ {
+ if (!disposed) {
+ disposed = true;
+ ProjectService.SolutionClosed -= SolutionClosed;
+ ProjectService.SolutionLoaded -= SolutionLoaded;
+ codeCoverageControl.Dispose();
+ }
+ }
+
+ public void UpdateToolbar()
+ {
+ codeCoverageControl.UpdateToolbar();
+ }
+
+ public void ShowResults(CodeCoverageResults results)
+ {
+ codeCoverageControl.Clear();
+ if (results != null) {
+ codeCoverageControl.AddModules(results.Modules);
+ }
+ }
+
+ public void ClearCodeCoverageResults()
+ {
+ codeCoverageControl.Clear();
+ }
+
+ void SolutionLoaded(object sender, EventArgs e)
+ {
+ codeCoverageControl.UpdateToolbar();
+ }
+
+ void SolutionClosed(object sender, EventArgs e)
+ {
+ codeCoverageControl.UpdateToolbar();
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageProjectOptionsPanel.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageProjectOptionsPanel.cs
new file mode 100644
index 0000000000..cbd4dee52f
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageProjectOptionsPanel.cs
@@ -0,0 +1,69 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.SharpDevelop.Gui;
+using ICSharpCode.SharpDevelop.Gui.OptionPanels;
+using ICSharpCode.SharpDevelop.Project;
+using System;
+using System.IO;
+using System.Windows.Forms;
+using System.Xml;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoverageProjectOptionsPanel : AbstractProjectOptionPanel
+ {
+ static readonly string AssemblyListTextBoxName = "assemblyListTextBox";
+
+ TextBox assemblyListTextBox;
+
+ public CodeCoverageProjectOptionsPanel()
+ {
+ }
+
+ public override void LoadPanelContents()
+ {
+ SetupFromXmlStream(this.GetType().Assembly.GetManifestResourceStream("ICSharpCode.CodeCoverage.Resources.CodeCoverageProjectOptionsPanel.xfrm"));
+ InitializeHelper();
+
+ assemblyListTextBox = (TextBox)ControlDictionary[AssemblyListTextBoxName];
+
+ ReadNCoverSettings();
+
+ assemblyListTextBox.TextChanged += AssemblyListTextBoxTextChanged;
+ }
+
+ public override bool StorePanelContents()
+ {
+ SaveNCoverSettings();
+ IsDirty = false;
+ return true;
+ }
+
+ void AssemblyListTextBoxTextChanged(object sender, EventArgs e)
+ {
+ IsDirty = true;
+ }
+
+ void SaveNCoverSettings()
+ {
+ NCoverSettings settings = new NCoverSettings();
+ settings.AssemblyList = assemblyListTextBox.Text;
+ settings.Save(NCoverSettings.GetFileName(project));
+ }
+
+ void ReadNCoverSettings()
+ {
+ string settingsFileName = NCoverSettings.GetFileName(project);
+ if (File.Exists(settingsFileName)) {
+ NCoverSettings settings = new NCoverSettings(settingsFileName);
+ assemblyListTextBox.Text = settings.AssemblyList;
+ }
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageResults.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageResults.cs
new file mode 100644
index 0000000000..270e755f96
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageResults.cs
@@ -0,0 +1,102 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Xml;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoverageResults
+ {
+ List modules = new List();
+
+ public CodeCoverageResults(string fileName) : this(new StreamReader(fileName, true))
+ {
+ }
+
+ public CodeCoverageResults(XmlReader reader)
+ {
+ ReadResults(reader);
+ }
+
+ public CodeCoverageResults(TextReader reader) : this(new XmlTextReader(reader))
+ {
+ }
+
+ public List GetSequencePoints(string fileName)
+ {
+ List sequencePoints = new List();
+ foreach (CodeCoverageModule module in modules) {
+ sequencePoints.AddRange(module.GetSequencePoints(fileName));
+ }
+ return sequencePoints;
+ }
+
+ public List Modules {
+ get {
+ return modules;
+ }
+ }
+
+ void ReadResults(XmlReader reader)
+ {
+ CodeCoverageModule currentModule = null;
+ CodeCoverageMethod currentMethod = null;
+
+ while (reader.Read()) {
+ switch (reader.NodeType) {
+ case XmlNodeType.Element:
+ if (reader.Name == "module") {
+ currentModule = AddModule(reader);
+ } else if (reader.Name == "method" && currentModule != null) {
+ currentMethod = AddMethod(currentModule, reader);
+ } else if (reader.Name == "seqpnt" && currentMethod != null) {
+ AddSequencePoint(currentMethod, reader);
+ }
+ break;
+ }
+ }
+ reader.Close();
+ }
+
+ CodeCoverageModule AddModule(XmlReader reader)
+ {
+ CodeCoverageModule module = new CodeCoverageModule(reader.GetAttribute("assembly"));
+ modules.Add(module);
+ return module;
+ }
+
+ CodeCoverageMethod AddMethod(CodeCoverageModule module, XmlReader reader)
+ {
+ CodeCoverageMethod method = new CodeCoverageMethod(reader.GetAttribute("name"), reader.GetAttribute("class"));
+ module.Methods.Add(method);
+ return method;
+ }
+
+ void AddSequencePoint(CodeCoverageMethod method, XmlReader reader)
+ {
+ CodeCoverageSequencePoint sequencePoint = new CodeCoverageSequencePoint(reader.GetAttribute("document"),
+ GetInteger(reader.GetAttribute("visitcount")),
+ GetInteger(reader.GetAttribute("line")),
+ GetInteger(reader.GetAttribute("column")),
+ GetInteger(reader.GetAttribute("endline")),
+ GetInteger(reader.GetAttribute("endcolumn")));
+ method.SequencePoints.Add(sequencePoint);
+ }
+
+ int GetInteger(string s)
+ {
+ int val;
+ if (Int32.TryParse(s, out val)) {
+ return val;
+ }
+ return 0;
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageRunnerNotFoundForm.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageRunnerNotFoundForm.cs
new file mode 100644
index 0000000000..44b3165fb4
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageRunnerNotFoundForm.cs
@@ -0,0 +1,33 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.SharpDevelop;
+using ICSharpCode.SharpDevelop.Gui.XmlForms;
+using System;
+using System.Diagnostics;
+using System.Windows.Forms;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoverageRunnerNotFoundForm : XmlForm
+ {
+ public CodeCoverageRunnerNotFoundForm()
+ {
+ SetupFromXmlStream(this.GetType().Assembly.GetManifestResourceStream("ICSharpCode.CodeCoverage.Resources.CodeCoverageRunnerNotFoundForm.xfrm"));
+
+ ((Label)ControlDictionary["messageLabel"]).Text = "Unable to locate the NCover console application.\n\nIf NCover is installed, please specify the location of the application in the Code Coverage options.";
+ ((PictureBox)ControlDictionary["iconPictureBox"]).Image = ResourceService.GetBitmap("Icons.32x32.Information");
+ ((LinkLabel)ControlDictionary["linkLabel"]).Click += LinkLabelClicked;
+ }
+
+ void LinkLabelClicked(object sender, EventArgs e)
+ {
+ Process.Start("http://ncover.org");
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageSequencePoint.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageSequencePoint.cs
new file mode 100644
index 0000000000..f7b7cc99f2
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageSequencePoint.cs
@@ -0,0 +1,67 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoverageSequencePoint
+ {
+ string document = String.Empty;
+ int visitCount = 0;
+ int line = 0;
+ int column = 0;
+ int endLine = 0;
+ int endColumn = 0;
+
+ public CodeCoverageSequencePoint(string document, int visitCount, int line, int column, int endLine, int endColumn)
+ {
+ this.document = document;
+ this.visitCount = visitCount;
+ this.line = line;
+ this.column = column;
+ this.endLine = endLine;
+ this.endColumn = endColumn;
+ }
+
+ public string Document {
+ get {
+ return document;
+ }
+ }
+
+ public int VisitCount {
+ get {
+ return visitCount;
+ }
+ }
+
+ public int Line {
+ get {
+ return line;
+ }
+ }
+
+ public int Column {
+ get {
+ return column;
+ }
+ }
+
+ public int EndLine {
+ get {
+ return endLine;
+ }
+ }
+
+ public int EndColumn {
+ get {
+ return endColumn;
+ }
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageService.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageService.cs
new file mode 100644
index 0000000000..2808e7e261
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageService.cs
@@ -0,0 +1,150 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
+using ICSharpCode.SharpDevelop.Gui;
+using ICSharpCode.SharpDevelop.Project;
+using System;
+using System.Collections.Generic;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoverageService
+ {
+ static CodeCoverageResults results;
+ static CodeCoverageHighlighter codeCoverageHighlighter = new CodeCoverageHighlighter();
+
+ CodeCoverageService()
+ {
+ }
+
+ static CodeCoverageService()
+ {
+ WorkbenchSingleton.Workbench.ViewOpened += ViewOpened;
+ }
+
+ ///
+ /// Shows/hides the code coverage in the source code.
+ ///
+ public static bool CodeCoverageHighlighted {
+ get {
+ return CodeCoverageOptions.CodeCoverageHighlighted;
+ }
+ set {
+ CodeCoveragePad pad = CodeCoveragePad.Instance;
+ if (pad != null) {
+ pad.UpdateToolbar();
+ }
+ if (CodeCoverageOptions.CodeCoverageHighlighted != value) {
+ CodeCoverageOptions.CodeCoverageHighlighted = value;
+ if (CodeCoverageResultsExist) {
+ if (CodeCoverageOptions.CodeCoverageHighlighted) {
+ ShowCodeCoverage();
+ } else {
+ HideCodeCoverage();
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Gets the results from the last code coverage run.
+ ///
+ public static CodeCoverageResults Results {
+ get {
+ return results;
+ }
+ }
+
+ ///
+ /// Clears any code coverage results currently on display.
+ ///
+ public static void ClearResults()
+ {
+ CodeCoveragePad pad = CodeCoveragePad.Instance;
+ if (pad != null) {
+ pad.ClearCodeCoverageResults();
+ }
+ HideCodeCoverage();
+ results = null;
+ }
+
+ ///
+ /// Shows the code coverage results in the code coverage pad and
+ /// highlights any source code files that have been profiled.
+ ///
+ public static void ShowResults(CodeCoverageResults results)
+ {
+ CodeCoverageService.results = results;
+ CodeCoveragePad pad = CodeCoveragePad.Instance;
+ if (pad != null) {
+ pad.ShowResults(results);
+ }
+ if (results != null) {
+ RefreshCodeCoverageHighlights();
+ }
+ }
+
+ ///
+ /// Updates the highlighted code coverage text to reflect any changes
+ /// in the configured colours.
+ ///
+ public static void RefreshCodeCoverageHighlights()
+ {
+ if (CodeCoverageOptions.CodeCoverageHighlighted && CodeCoverageResultsExist) {
+ HideCodeCoverage();
+ ShowCodeCoverage();
+ }
+ }
+
+ static void ShowCodeCoverage()
+ {
+ // Highlight any open files.
+ foreach (IViewContent view in WorkbenchSingleton.Workbench.ViewContentCollection) {
+ ShowCodeCoverage(view);
+ }
+ }
+
+ static void HideCodeCoverage()
+ {
+ foreach (IViewContent view in WorkbenchSingleton.Workbench.ViewContentCollection) {
+ TextEditorDisplayBindingWrapper textEditor = view as TextEditorDisplayBindingWrapper;
+ if (textEditor != null) {
+ codeCoverageHighlighter.RemoveMarkers(textEditor.textAreaControl.Document.MarkerStrategy);
+ textEditor.textAreaControl.Refresh();
+ }
+ }
+ }
+
+ static void ViewOpened(object sender, ViewContentEventArgs e)
+ {
+ if (CodeCoverageOptions.CodeCoverageHighlighted && CodeCoverageResultsExist) {
+ ShowCodeCoverage(e.Content);
+ }
+ }
+
+ static void ShowCodeCoverage(IViewContent view)
+ {
+ TextEditorDisplayBindingWrapper textEditor = view as TextEditorDisplayBindingWrapper;
+ if (textEditor != null && view.FileName != null) {
+ List sequencePoints = results.GetSequencePoints(view.FileName);
+ if (sequencePoints.Count > 0) {
+ codeCoverageHighlighter.AddMarkers(textEditor.textAreaControl.Document.MarkerStrategy, sequencePoints);
+ textEditor.textAreaControl.Refresh();
+ }
+ }
+ }
+
+ static bool CodeCoverageResultsExist {
+ get {
+ return results != null;
+ }
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageTextMarker.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageTextMarker.cs
new file mode 100644
index 0000000000..d2a1a18b41
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageTextMarker.cs
@@ -0,0 +1,49 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.TextEditor.Document;
+using System;
+using System.Drawing;
+
+namespace ICSharpCode.CodeCoverage
+{
+ ///
+ /// Custom text marker used when highlighting code coverage lines.
+ ///
+ public class CodeCoverageTextMarker : TextMarker
+ {
+ public CodeCoverageTextMarker(int offset, CodeCoverageSequencePoint sequencePoint) : this(offset, GetSequencePointLength(sequencePoint), sequencePoint)
+ {
+ }
+
+ public CodeCoverageTextMarker(int offset, int length, CodeCoverageSequencePoint sequencePoint) : base(offset, length, TextMarkerType.SolidBlock, GetSequencePointColor(sequencePoint), GetSequencePointForeColor(sequencePoint))
+ {
+ }
+
+ public static int GetSequencePointLength(CodeCoverageSequencePoint sequencePoint)
+ {
+ return sequencePoint.EndColumn - sequencePoint.Column;
+ }
+
+ public static Color GetSequencePointColor(CodeCoverageSequencePoint sequencePoint)
+ {
+ if (sequencePoint.VisitCount > 0) {
+ return CodeCoverageOptions.VisitedColor;
+ }
+ return CodeCoverageOptions.NotVisitedColor;
+ }
+
+ public static Color GetSequencePointForeColor(CodeCoverageSequencePoint sequencePoint)
+ {
+ if (sequencePoint.VisitCount > 0) {
+ return CodeCoverageOptions.VisitedForeColor;
+ }
+ return CodeCoverageOptions.NotVisitedForeColor;
+ }
+
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageTreeNode.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageTreeNode.cs
new file mode 100644
index 0000000000..f392a519ab
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageTreeNode.cs
@@ -0,0 +1,83 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.SharpDevelop.Gui;
+using System;
+using System.Drawing;
+using System.Collections.Generic;
+using System.Windows.Forms;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoverageTreeNode : ExtTreeNode
+ {
+ public static readonly Color PartialCoverageTextColor = Color.Red;
+
+ int visitedCount;
+ int notVisitedCount;
+
+ public CodeCoverageTreeNode(string name) : this(name, 0, 0)
+ {
+ }
+
+ public CodeCoverageTreeNode(string name, int visitedCount, int notVisitedCount)
+ {
+ this.visitedCount = visitedCount;
+ this.notVisitedCount = notVisitedCount;
+
+ Name = name;
+ SetText();
+ }
+
+ public int VisitedCount {
+ get {
+ return visitedCount;
+ }
+ set {
+ visitedCount = value;
+ SetText();
+ }
+ }
+
+ public int NotVisitedCount {
+ get {
+ return notVisitedCount;
+ }
+ set {
+ notVisitedCount = value;
+ SetText();
+ }
+ }
+
+ static string GetPercentage(int visitedCount, int totalCount)
+ {
+ int percentage = (visitedCount * 100) / totalCount;
+ return percentage.ToString();
+ }
+
+ static string GetNodeText(string name, int visitedCount, int totalCount)
+ {
+ if (totalCount > 0) {
+ return String.Concat(name, " (", GetPercentage(visitedCount, totalCount), "%)");
+ }
+ return name;
+ }
+
+ void SetText()
+ {
+ int total = visitedCount + notVisitedCount;
+
+ // Change the text color for partial coverage.
+ if (total != visitedCount) {
+ ForeColor = PartialCoverageTextColor;
+ }
+
+ // Get the text for the node.
+ Text = GetNodeText(Name, visitedCount, total);
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageTreeView.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageTreeView.cs
new file mode 100644
index 0000000000..c958e0dc79
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/CodeCoverageTreeView.cs
@@ -0,0 +1,29 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.SharpDevelop.Gui;
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class CodeCoverageTreeView : ExtTreeView
+ {
+ public CodeCoverageTreeView()
+ {
+ }
+
+ public void AddModules(List modules)
+ {
+ foreach (CodeCoverageModule module in modules) {
+ Nodes.Add(new CodeCoverageModuleTreeNode(module));
+ }
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/ColorPickerComboBox.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/ColorPickerComboBox.cs
new file mode 100644
index 0000000000..d879ba05a5
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/ColorPickerComboBox.cs
@@ -0,0 +1,144 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class ColorPickerComboBox : System.Windows.Forms.ComboBox
+ {
+ Color customColor = Color.Empty;
+ int ColorRectangleLeftOffset = 4;
+ int ColorRectangleTopOffset = 2;
+
+ public ColorPickerComboBox()
+ {
+ base.DropDownStyle = ComboBoxStyle.DropDownList;
+ DrawMode = DrawMode.OwnerDrawFixed;
+ AddBasicColors();
+ }
+
+ public Color SelectedColor {
+ get {
+ if (SelectedItem != null) {
+ return (Color)SelectedItem;
+ }
+ return Color.Empty;
+ }
+ set {
+ if (Items.Contains(value)) {
+ SelectedItem = value;
+ } else if (CustomColorExists) {
+ UpdateCustomColor(value);
+ } else {
+ AddCustomColor(value);
+ }
+ }
+ }
+
+ protected override void OnDrawItem(DrawItemEventArgs e)
+ {
+ if (e.Index >= 0) {
+ e.DrawBackground();
+ Graphics g = e.Graphics;
+ Color color = (Color)Items[e.Index];
+ Rectangle colorRectangle = GetColorRectangle(e.Bounds.Top);
+ g.FillRectangle(new SolidBrush(color), colorRectangle);
+ g.DrawRectangle(Pens.Black, colorRectangle);
+ int textOffset = (2 * colorRectangle.Left) + colorRectangle.Width;
+ SolidBrush brush = GetTextBrush(IsSelected(e.State));
+ g.DrawString(GetColorName(color), e.Font, brush, new Rectangle(textOffset, e.Bounds.Top, e.Bounds.Width - textOffset, ItemHeight));
+ }
+ base.OnDrawItem(e);
+ }
+
+ bool CustomColorExists {
+ get {
+ return customColor != Color.Empty;
+ }
+ }
+
+ void AddBasicColors()
+ {
+ Items.Add(Color.Black);
+ Items.Add(Color.White);
+ Items.Add(Color.Maroon);
+ Items.Add(Color.Green);
+ Items.Add(Color.Olive);
+ Items.Add(Color.Navy);
+ Items.Add(Color.Purple);
+ Items.Add(Color.Teal);
+ Items.Add(Color.Silver);
+ Items.Add(Color.Gray);
+ Items.Add(Color.Red);
+ Items.Add(Color.Lime);
+ Items.Add(Color.Yellow);
+ Items.Add(Color.Blue);
+ Items.Add(Color.Magenta);
+ Items.Add(Color.Cyan);
+ SelectedIndex = 0;
+ }
+
+ void AddCustomColor(Color color)
+ {
+ customColor = color;
+ SelectedIndex = Items.Add(color);
+ }
+
+ void UpdateCustomColor(Color color)
+ {
+ int index = Items.IndexOf(customColor);
+ if (index >= 0) {
+ customColor = color;
+ Items[index] = color;
+ SelectedIndex = index;
+ } else {
+ AddCustomColor(color);
+ }
+ }
+
+ Rectangle GetColorRectangle(int y)
+ {
+ int colorRectangleHeight = ItemHeight - (2 * ColorRectangleTopOffset);
+ return new Rectangle(ColorRectangleLeftOffset, y + ColorRectangleTopOffset, colorRectangleHeight, colorRectangleHeight);
+ }
+
+ string GetColorName(Color color)
+ {
+ if (CustomColorExists && color == customColor) {
+ return "Custom";
+ }
+ return color.Name;
+ }
+
+ SolidBrush GetTextBrush(bool selected)
+ {
+ if (selected) {
+ return new SolidBrush(Color.White);
+ }
+ return new SolidBrush(ForeColor);
+ }
+
+ bool IsSelected(DrawItemState state)
+ {
+ return (state & DrawItemState.Selected) == DrawItemState.Selected;
+ }
+
+ protected override void OnDropDownStyleChanged(EventArgs e)
+ {
+ if (DropDownStyle != ComboBoxStyle.DropDownList) {
+ DropDownStyle = ComboBoxStyle.DropDownList;
+ }
+ base.OnDropDownStyleChanged(e);
+ }
+
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/LineReceivedEventArgs.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/LineReceivedEventArgs.cs
new file mode 100644
index 0000000000..2ac07988a5
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/LineReceivedEventArgs.cs
@@ -0,0 +1,32 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public delegate void LineReceivedEventHandler(object sender, LineReceivedEventArgs e);
+
+ ///
+ /// The arguments for the event.
+ ///
+ public class LineReceivedEventArgs : EventArgs
+ {
+ string line = String.Empty;
+
+ public LineReceivedEventArgs(string line)
+ {
+ this.line = line;
+ }
+
+ public string Line {
+ get {
+ return line;
+ }
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/MbUnitResults.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/MbUnitResults.cs
new file mode 100644
index 0000000000..610a4cc677
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/MbUnitResults.cs
@@ -0,0 +1,113 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.SharpDevelop.Gui;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Xml;
+
+namespace ICSharpCode.CodeCoverage
+{
+ ///
+ /// Reads the MbUnit results file.
+ ///
+ public class MbUnitResults
+ {
+ static readonly string RunElementName = "run";
+ static readonly string MessageElementName = "message";
+ static readonly string StackTraceElementName= "stack-trace";
+
+ List tasks = new List();
+
+ public MbUnitResults(string fileName) : this(new StreamReader(fileName, true))
+ {
+ }
+
+ public MbUnitResults(XmlTextReader reader)
+ {
+ ReadResults(reader);
+ }
+
+ public MbUnitResults(TextReader reader) : this(new XmlTextReader(reader))
+ {
+ }
+
+ public List Tasks {
+ get {
+ return tasks;
+ }
+ }
+
+ void ReadResults(XmlTextReader reader)
+ {
+ using (reader) {
+ while (reader.Read()) {
+ if (reader.NodeType == XmlNodeType.Element) {
+ if (IsRunFailureElement(reader)) {
+ ReadErrorTask(reader);
+ }
+ }
+ }
+ }
+ }
+
+ bool IsRunFailureElement(XmlReader reader)
+ {
+ if (reader.Name == RunElementName) {
+ string result = reader.GetAttribute("result");
+ if (result != null && result == "failure") {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void ReadErrorTask(XmlReader reader)
+ {
+ string testCase = reader.GetAttribute("name");
+ string message = String.Empty;
+
+ while (reader.Read()) {
+ if (reader.NodeType == XmlNodeType.Element) {
+ if (reader.Name == MessageElementName) {
+ message = reader.ReadElementString();
+ } else if (reader.Name == StackTraceElementName) {
+ string stackTrace = reader.ReadElementString();
+ AddTask(GetDescription(testCase, message), stackTrace);
+ return;
+ }
+ }
+ }
+ }
+
+ ///
+ /// Gets task error description.
+ ///
+ string GetDescription(string testCase, string message)
+ {
+ return StringParser.Parse("${res:NUnitPad.NUnitPadContent.TestTreeView.TestFailedMessage}", new string[,] {
+ {"TestCase", testCase},
+ {"Message", message}
+ });
+ }
+
+ void AddTask(string description, string stackTrace)
+ {
+ FileLineReference lineRef = OutputTextLineParser.GetNUnitOutputFileLineReference(stackTrace, true);
+ if (lineRef != null) {
+ Task task = new Task(Path.GetFullPath(lineRef.FileName),
+ description,
+ lineRef.Column,
+ lineRef.Line,
+ TaskType.Error);
+ tasks.Add(task);
+ }
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/NCoverExitEventArgs.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/NCoverExitEventArgs.cs
new file mode 100644
index 0000000000..6ff17347f2
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/NCoverExitEventArgs.cs
@@ -0,0 +1,58 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+
+namespace ICSharpCode.CodeCoverage
+{
+ ///
+ /// Represents the method that will handle the
+ /// event.
+ ///
+ public delegate void NCoverExitEventHandler(object sender, NCoverExitEventArgs e);
+
+ ///
+ /// The event arguments.
+ ///
+ public class NCoverExitEventArgs : EventArgs
+ {
+ string output;
+ int exitCode;
+ string error;
+
+ public NCoverExitEventArgs(string output, string error, int exitCode)
+ {
+ this.output = output;
+ this.error = error;
+ this.exitCode = exitCode;
+ }
+
+ ///
+ /// Gets the command line output from NAnt.
+ ///
+ public string Output {
+ get {
+ return output;
+ }
+ }
+
+ public string Error {
+ get {
+ return error;
+ }
+ }
+
+ ///
+ /// Gets the exit code.
+ ///
+ public int ExitCode {
+ get {
+ return exitCode;
+ }
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/NCoverRunner.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/NCoverRunner.cs
new file mode 100644
index 0000000000..0b8b2f3c1a
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/NCoverRunner.cs
@@ -0,0 +1,255 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Diagnostics;
+using System.Text;
+
+namespace ICSharpCode.CodeCoverage
+{
+ ///
+ /// Runs NCover.
+ ///
+ public class NCoverRunner
+ {
+ string ncoverFileName = String.Empty;
+ string workingDirectory = String.Empty;
+ string coverageResultsFileName = String.Empty;
+ string profiledApplicationCommand = String.Empty;
+ string profiledApplicationCommandLineArguments = String.Empty;
+ string assemblyList = String.Empty;
+ string logFileName = String.Empty;
+ ProcessRunner runner;
+
+ ///
+ /// Triggered when NCover exits.
+ ///
+ public event NCoverExitEventHandler NCoverExited;
+
+ ///
+ /// The NCover runner was started.
+ ///
+ public event EventHandler NCoverStarted;
+
+ ///
+ /// The NCover runner was stopped. Being stopped is not the
+ /// same as NCover exiting.
+ ///
+ public event EventHandler NCoverStopped;
+
+ ///
+ /// Triggered when an output line is received from NCover.
+ ///
+ public event LineReceivedEventHandler OutputLineReceived;
+
+ public NCoverRunner()
+ {
+ }
+
+ ///
+ /// Gets or sets the NCover executable path.
+ ///
+ public string NCoverFileName {
+ get {
+ return ncoverFileName;
+ }
+ set {
+ ncoverFileName = value;
+ }
+ }
+
+ public string WorkingDirectory {
+ get {
+ return workingDirectory;
+ }
+ set {
+ workingDirectory = value;
+ }
+ }
+
+ ///
+ /// The list of assemblies that will be profiled.
+ ///
+ public string AssemblyList {
+ get {
+ return assemblyList;
+ }
+ set {
+ // Remove any spaces from the assembly list since
+ // NCover will ignore any items after the space.
+ assemblyList = value.Replace(" ", String.Empty);
+ }
+ }
+
+ ///
+ /// Gets the full NCover command line that will be used by
+ /// the runner.
+ ///
+ public string CommandLine {
+ get {
+ return String.Concat(ncoverFileName, " ", GetArguments());
+ }
+ }
+
+ ///
+ /// Gets whether the NCover runner is currently running.
+ ///
+ public bool IsRunning {
+ get {
+ if (runner != null) {
+ return runner.IsRunning;
+ }
+ return false;
+ }
+ }
+
+ ///
+ /// Coverage output results file.
+ ///
+ public string CoverageResultsFileName {
+ get {
+ return coverageResultsFileName;
+ }
+ set {
+ coverageResultsFileName = value;
+ }
+ }
+
+ ///
+ /// Profiler log file.
+ ///
+ public string LogFileName {
+ get {
+ return logFileName;
+ }
+ set {
+ logFileName = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the command that will be used to run the
+ /// profiled application.
+ ///
+ public string ProfiledApplicationCommand {
+ get {
+ return profiledApplicationCommand;
+ }
+ set {
+ profiledApplicationCommand = value;
+ }
+ }
+
+ ///
+ /// The arguments that will be used with the profiled application.
+ ///
+ public string ProfiledApplicationCommandLineArguments {
+ get {
+ return profiledApplicationCommandLineArguments;
+ }
+ set {
+ profiledApplicationCommandLineArguments = value;
+ }
+ }
+
+ public void Start()
+ {
+ string arguments = GetArguments();
+
+ runner = new ProcessRunner();
+ runner.WorkingDirectory = workingDirectory;
+ runner.ProcessExited += new EventHandler(ProcessExited);
+
+ if (OutputLineReceived != null) {
+ runner.OutputLineReceived += new LineReceivedEventHandler(OnOutputLineReceived);
+ }
+ runner.Start(ncoverFileName, arguments);
+ OnNCoverStarted();
+ }
+
+ ///
+ /// Stops the currently running NCover instance.
+ ///
+ public void Stop()
+ {
+ if (runner != null) {
+ runner.Kill();
+ OnNCoverStopped();
+ }
+ }
+
+ protected void OnNCoverExited(string output, string error, int exitCode)
+ {
+ if (NCoverExited != null) {
+ NCoverExited(this, new NCoverExitEventArgs(output, error, exitCode));
+ }
+ }
+
+ protected void OnNCoverStarted()
+ {
+ if (NCoverStarted != null) {
+ NCoverStarted(this, new EventArgs());
+ }
+ }
+
+ protected void OnNCoverStopped()
+ {
+ if (NCoverStopped != null) {
+ NCoverStopped(this, new EventArgs());
+ }
+ }
+
+ ///
+ /// Raises the event.
+ ///
+ /// The event source.
+ /// The event arguments.
+ protected void OnOutputLineReceived(object sender, LineReceivedEventArgs e)
+ {
+ if (OutputLineReceived != null) {
+ OutputLineReceived(this, e);
+ }
+ }
+
+ ///
+ /// Handles the NCover process exit event.
+ ///
+ /// The event source.
+ /// The event arguments.
+ void ProcessExited(object sender, EventArgs e)
+ {
+ ProcessRunner runner = (ProcessRunner)sender;
+ OnNCoverExited(runner.StandardOutput, runner.StandardError, runner.ExitCode);
+ }
+
+ ///
+ /// Adds extra command line arguments to those specified
+ /// by the user in the string.
+ ///
+ string GetArguments()
+ {
+ StringBuilder ncoverArguments = new StringBuilder();
+
+ if (coverageResultsFileName.Length > 0) {
+ ncoverArguments.AppendFormat("//x \"{0}\" ", coverageResultsFileName);
+ }
+
+ if (assemblyList.Length > 0) {
+ ncoverArguments.AppendFormat("//a \"{0}\" ", assemblyList);
+ }
+
+ if (logFileName.Length > 0) {
+ ncoverArguments.AppendFormat("//l \"{0}\" ", logFileName);
+ }
+
+ ncoverArguments.AppendFormat("\"{0}\" ", profiledApplicationCommand);
+ ncoverArguments.Append(profiledApplicationCommandLineArguments);
+
+ return ncoverArguments.ToString();
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/NCoverRunnerSingleton.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/NCoverRunnerSingleton.cs
new file mode 100644
index 0000000000..b08c7f94c6
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/NCoverRunnerSingleton.cs
@@ -0,0 +1,36 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+
+namespace ICSharpCode.CodeCoverage
+{
+ ///
+ /// Single NCover runner that is used by all commands.
+ ///
+ ///
+ public class NCoverRunnerSingleton
+ {
+ static NCoverRunner runner;
+
+ NCoverRunnerSingleton()
+ {
+ }
+
+ ///
+ /// Gets the instance.
+ ///
+ public static NCoverRunner Runner {
+ get {
+ if (runner == null) {
+ runner = new NCoverRunner();
+ }
+ return runner;
+ }
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/NCoverSettings.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/NCoverSettings.cs
new file mode 100644
index 0000000000..04f4095db8
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/NCoverSettings.cs
@@ -0,0 +1,97 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.SharpDevelop.Project;
+using System;
+using System.IO;
+using System.Text;
+using System.Xml;
+
+namespace ICSharpCode.CodeCoverage
+{
+ ///
+ /// Settings for NCover.
+ ///
+ public class NCoverSettings
+ {
+ static readonly string RootElementName = "ProfilerSettings";
+ static readonly string AssembliesElementName = "Assemblies";
+
+ string assemblyList = String.Empty;
+
+ public NCoverSettings()
+ {
+ }
+
+ public NCoverSettings(string fileName) : this(new StreamReader(fileName, true))
+ {
+ }
+
+ public NCoverSettings(XmlReader reader)
+ {
+ ReadSettings(reader);
+ }
+
+ public NCoverSettings(TextReader reader) : this(new XmlTextReader(reader))
+ {
+ }
+
+ ///
+ /// Gets the NCover settings filename for the specified project.
+ ///
+ public static string GetFileName(IProject project)
+ {
+ return Path.ChangeExtension(project.FileName, "NCover.Settings");
+ }
+
+ ///
+ /// A semi-colon delimited list of assemblies.
+ ///
+ public string AssemblyList {
+ get {
+ return assemblyList;
+ }
+ set {
+ assemblyList = value;
+ }
+ }
+
+ public void Save(TextWriter writer)
+ {
+ Save(new XmlTextWriter(writer));
+ }
+
+ public void Save(string fileName)
+ {
+ Save(new StreamWriter(fileName, false, Encoding.UTF8));
+ }
+
+ public void Save(XmlTextWriter writer)
+ {
+ writer.Formatting = Formatting.Indented;
+
+ using (writer) {
+ writer.WriteStartElement(RootElementName);
+ writer.WriteElementString(AssembliesElementName, assemblyList);
+ writer.WriteEndElement();
+ }
+ }
+
+ void ReadSettings(XmlReader reader)
+ {
+ using (reader) {
+ while (reader.Read()) {
+ if (reader.NodeType == XmlNodeType.Element) {
+ if (reader.Name == AssembliesElementName) {
+ assemblyList = reader.ReadString();
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/OutputReader.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/OutputReader.cs
new file mode 100644
index 0000000000..a05f7e14d7
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/OutputReader.cs
@@ -0,0 +1,98 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using System.Threading;
+
+namespace ICSharpCode.CodeCoverage
+{
+ ///
+ /// A threaded or
+ /// reader.
+ ///
+ public class OutputReader
+ {
+ StreamReader reader;
+ string output = String.Empty;
+ Thread thread;
+
+ public event LineReceivedEventHandler LineReceived;
+
+ public OutputReader(StreamReader reader)
+ {
+ this.reader = reader;
+ }
+
+ ///
+ /// Starts reading the output stream.
+ ///
+ public void Start()
+ {
+ thread = new Thread(new ThreadStart(ReadOutput));
+ thread.Start();
+ }
+
+ ///
+ /// Gets the text output read from the reader.
+ ///
+ public string Output {
+ get {
+ return output;
+ }
+ }
+
+ ///
+ /// Waits for the reader to finish.
+ ///
+ public void WaitForFinish()
+ {
+ if (thread != null) {
+ thread.Join();
+ }
+ }
+
+ ///
+ /// Raises the event.
+ ///
+ ///
+ protected void OnLineReceived(string line)
+ {
+ if (LineReceived != null) {
+ LineReceived(this, new LineReceivedEventArgs(line));
+ }
+ }
+
+ ///
+ /// Reads the output stream on a different thread.
+ ///
+ void ReadOutput()
+ {
+ //output = reader.ReadToEnd();
+ output = String.Empty;
+ StringBuilder outputBuilder = new StringBuilder();
+
+ bool endOfStream = false;
+ while(!endOfStream)
+ {
+ string line = reader.ReadLine();
+
+ if (line != null) {
+ outputBuilder.Append(line);
+ outputBuilder.Append(Environment.NewLine);
+ OnLineReceived(line);
+ } else {
+ endOfStream = true;
+ }
+ }
+
+ output = outputBuilder.ToString();
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/ProcessRunner.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/ProcessRunner.cs
new file mode 100644
index 0000000000..e424b19aa4
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/ProcessRunner.cs
@@ -0,0 +1,266 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+namespace ICSharpCode.CodeCoverage
+{
+ ///
+ /// Runs a process that sends output to standard output and to
+ /// standard error.
+ ///
+ public class ProcessRunner : IDisposable
+ {
+ Process process;
+ string standardOutput = String.Empty;
+ string workingDirectory = String.Empty;
+ OutputReader standardOutputReader;
+ OutputReader standardErrorReader;
+
+ ///
+ /// Triggered when the process has exited.
+ ///
+ public event EventHandler ProcessExited;
+
+ ///
+ /// Triggered when a line of text is read from the standard output.
+ ///
+ public event LineReceivedEventHandler OutputLineReceived;
+
+ ///
+ /// Triggered when a line of text is read from the standard error.
+ ///
+ public event LineReceivedEventHandler ErrorLineReceived;
+
+ ///
+ /// Creates a new instance of the .
+ ///
+ public ProcessRunner()
+ {
+ }
+
+ ///
+ /// Gets or sets the process's working directory.
+ ///
+ public string WorkingDirectory {
+ get {
+ return workingDirectory;
+ }
+
+ set {
+ workingDirectory = value;
+ }
+ }
+
+ ///
+ /// Gets the standard output returned from the process.
+ ///
+ public string StandardOutput {
+ get {
+ string output = String.Empty;
+ if (standardOutputReader != null) {
+ output = standardOutputReader.Output;
+ }
+ return output;
+ }
+ }
+
+ ///
+ /// Gets the standard error output returned from the process.
+ ///
+ public string StandardError {
+ get {
+ string output = String.Empty;
+ if (standardErrorReader != null) {
+ output = standardErrorReader.Output;
+ }
+ return output;
+ }
+ }
+
+ ///
+ /// Releases resources held by the
+ ///
+ public void Dispose()
+ {
+ }
+
+ ///
+ /// Gets the process exit code.
+ ///
+ public int ExitCode {
+ get {
+ int exitCode = 0;
+ if (process != null) {
+ exitCode = process.ExitCode;
+ }
+ return exitCode;
+ }
+ }
+
+ ///
+ /// Waits for the process to exit.
+ ///
+ public void WaitForExit()
+ {
+ WaitForExit(Int32.MaxValue);
+ }
+
+ ///
+ /// Waits for the process to exit.
+ ///
+ /// A timeout in milliseconds.
+ /// if the associated process has
+ /// exited; otherwise,
+ public bool WaitForExit(int timeout)
+ {
+ if (process == null) {
+ throw new ProcessRunnerException(StringParser.Parse("${res:ICSharpCode.NAntAddIn.ProcessRunner.NoProcessRunningErrorText}"));
+ }
+
+ bool exited = process.WaitForExit(timeout);
+
+ if (exited) {
+ standardOutputReader.WaitForFinish();
+ standardErrorReader.WaitForFinish();
+ }
+
+ return exited;
+ }
+
+ public bool IsRunning {
+ get {
+ bool isRunning = false;
+
+ if (process != null) {
+ isRunning = !process.HasExited;
+ }
+
+ return isRunning;
+ }
+ }
+
+ ///
+ /// Starts the process.
+ ///
+ /// The process filename.
+ /// The command line arguments to
+ /// pass to the command.
+ public void Start(string command, string arguments)
+ {
+ process = new Process();
+ process.StartInfo.CreateNoWindow = true;
+ process.StartInfo.FileName = command;
+ process.StartInfo.WorkingDirectory = workingDirectory;
+ process.StartInfo.RedirectStandardOutput = true;
+ process.StartInfo.RedirectStandardError = true;
+ process.StartInfo.UseShellExecute = false;
+ process.StartInfo.Arguments = arguments;
+
+ if (ProcessExited != null) {
+ process.EnableRaisingEvents = true;
+ process.Exited += new EventHandler(OnProcessExited);
+ }
+
+ process.Start();
+
+ standardOutputReader = new OutputReader(process.StandardOutput);
+ if (OutputLineReceived != null) {
+ standardOutputReader.LineReceived += new LineReceivedEventHandler(OnOutputLineReceived);
+ }
+
+ standardOutputReader.Start();
+
+ standardErrorReader = new OutputReader(process.StandardError);
+ if (ErrorLineReceived != null) {
+ standardErrorReader.LineReceived += new LineReceivedEventHandler(OnErrorLineReceived);
+ }
+
+ standardErrorReader.Start();
+ }
+
+ ///
+ /// Starts the process.
+ ///
+ /// The process filename.
+ public void Start(string command)
+ {
+ Start(command, String.Empty);
+ }
+
+ ///
+ /// Kills the running process.
+ ///
+ public void Kill()
+ {
+ if (process != null) {
+ if (!process.HasExited) {
+ process.Kill();
+ process.Close();
+ process.Dispose();
+ process = null;
+ standardOutputReader.WaitForFinish();
+ standardErrorReader.WaitForFinish();
+ } else {
+ process = null;
+ }
+ }
+ // Control-C does not seem to work.
+ //GenerateConsoleCtrlEvent((int)ConsoleEvent.ControlC, 0);
+ }
+
+ ///
+ /// Raises the event.
+ ///
+ protected void OnProcessExited(object sender, EventArgs e)
+ {
+ if (ProcessExited != null) {
+
+ standardOutputReader.WaitForFinish();
+ standardErrorReader.WaitForFinish();
+
+ ProcessExited(this, e);
+ }
+ }
+
+ ///
+ /// Raises the event.
+ ///
+ /// The event source.
+ /// The line received event arguments.
+ protected void OnOutputLineReceived(object sender, LineReceivedEventArgs e)
+ {
+ if (OutputLineReceived != null) {
+ OutputLineReceived(this, e);
+ }
+ }
+
+ ///
+ /// Raises the event.
+ ///
+ /// The event source.
+ /// The line received event arguments.
+ protected void OnErrorLineReceived(object sender, LineReceivedEventArgs e)
+ {
+ if (ErrorLineReceived != null) {
+ ErrorLineReceived(this, e);
+ }
+ }
+
+ enum ConsoleEvent
+ {
+ ControlC = 0,
+ ControlBreak = 1
+ };
+
+ [DllImport("kernel32.dll", SetLastError=true)]
+ static extern int GenerateConsoleCtrlEvent(int dwCtrlEvent, int dwProcessGroupId);
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/ProcessRunnerException.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/ProcessRunnerException.cs
new file mode 100644
index 0000000000..a5603a3d1b
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/ProcessRunnerException.cs
@@ -0,0 +1,23 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+
+namespace ICSharpCode.CodeCoverage
+{
+ ///
+ /// An exception thrown by a
+ /// instance.
+ ///
+ public class ProcessRunnerException : ApplicationException
+ {
+ public ProcessRunnerException(string message)
+ : base(message)
+ {
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/RunMbUnitPadTestsWithCodeCoverageCommand.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/RunMbUnitPadTestsWithCodeCoverageCommand.cs
new file mode 100644
index 0000000000..634ffa479c
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/RunMbUnitPadTestsWithCodeCoverageCommand.cs
@@ -0,0 +1,37 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.SharpDevelop.Project;
+using ICSharpCode.MbUnitPad;
+using System;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class RunMbUnitPadTestsWithCodeCoverageCommand : AbstractRunTestsWithCodeCoverageCommand
+ {
+ protected override string GetTestAssemblyFileName()
+ {
+ return MbUnitPadContent.Instance.SelectedAssemblyFileName;
+ }
+
+ protected override IProject GetProject()
+ {
+ return GetSelectedProject(GetTestAssemblyFileName());
+ }
+
+ IProject GetSelectedProject(string outputAssemblyFileName)
+ {
+ foreach (IProject project in ProjectService.OpenSolution.Projects) {
+ if (FileUtility.IsEqualFileName(outputAssemblyFileName, project.OutputAssemblyFullPath)) {
+ return project;
+ }
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/RunTestFixtureWithCodeCoverageCommand.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/RunTestFixtureWithCodeCoverageCommand.cs
new file mode 100644
index 0000000000..04b8a895a5
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/RunTestFixtureWithCodeCoverageCommand.cs
@@ -0,0 +1,47 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.SharpDevelop.Dom;
+using ICSharpCode.SharpDevelop.Project;
+using ICSharpCode.MbUnitPad;
+using System;
+
+namespace ICSharpCode.CodeCoverage
+{
+ ///
+ /// Menu command selected after right clicking a test fixture in the text editor
+ /// to run tests with code coverage.
+ ///
+ public class RunTestFixtureWithCodeCoverageCommand : AbstractRunTestsWithCodeCoverageCommand
+ {
+ IProject project;
+
+ public override void Run()
+ {
+ IMember m = MbUnitTestableCondition.GetMember(Owner);
+ IClass c = (m != null) ? m.DeclaringType : MbUnitTestableCondition.GetClass(Owner);
+ project = c.ProjectContent.Project;
+ if (project != null) {
+ base.Run();
+ } else {
+ MessageService.ShowMessage("Unable to determine project.");
+ }
+ }
+
+ protected override IProject GetProject()
+ {
+ return project;
+ }
+
+ protected override string GetTestAssemblyFileName()
+ {
+ return project.OutputAssemblyFullPath;
+ }
+ }
+}
+
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/RunTestWithCodeCoverageCommand.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/RunTestWithCodeCoverageCommand.cs
new file mode 100644
index 0000000000..8369827c7f
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/RunTestWithCodeCoverageCommand.cs
@@ -0,0 +1,46 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.SharpDevelop.Dom;
+using ICSharpCode.SharpDevelop.Project;
+using ICSharpCode.MbUnitPad;
+using System;
+
+namespace ICSharpCode.CodeCoverage
+{
+ ///
+ /// Menu command selected after right clicking a test method in the text editor
+ /// to run tests with code coverage.
+ ///
+ public class RunTestWithCodeCoverageCommand : AbstractRunTestsWithCodeCoverageCommand
+ {
+ IProject project;
+
+ public override void Run()
+ {
+ IMember m = MbUnitTestableCondition.GetMember(Owner);
+ IClass c = (m != null) ? m.DeclaringType : MbUnitTestableCondition.GetClass(Owner);
+ project = c.ProjectContent.Project;
+ if (project != null) {
+ base.Run();
+ } else {
+ MessageService.ShowMessage("Unable to determine project.");
+ }
+ }
+
+ protected override IProject GetProject()
+ {
+ return project;
+ }
+
+ protected override string GetTestAssemblyFileName()
+ {
+ return project.OutputAssemblyFullPath;
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Project/Src/ToggleCodeCoverageCommand.cs b/src/AddIns/Misc/CodeCoverage/Project/Src/ToggleCodeCoverageCommand.cs
new file mode 100644
index 0000000000..e3c21b2587
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Project/Src/ToggleCodeCoverageCommand.cs
@@ -0,0 +1,25 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.SharpDevelop;
+using System;
+
+namespace ICSharpCode.CodeCoverage
+{
+ public class ToggleCodeCoverageCommand : AbstractCheckableMenuCommand
+ {
+ public override bool IsChecked {
+ get {
+ return CodeCoverageService.CodeCoverageHighlighted;
+ }
+ set {
+ CodeCoverageService.CodeCoverageHighlighted = value;
+ }
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/AddCodeCoverageMarkersTestFixture.cs b/src/AddIns/Misc/CodeCoverage/Test/AddCodeCoverageMarkersTestFixture.cs
new file mode 100644
index 0000000000..ae6ca041de
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/AddCodeCoverageMarkersTestFixture.cs
@@ -0,0 +1,144 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.CodeCoverage;
+using ICSharpCode.TextEditor.Document;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace ICSharpCode.CodeCoverage.Tests
+{
+ [TestFixture]
+ public class AddCodeCoverageMarkersTestFixture
+ {
+ MarkerStrategy markerStrategy;
+ CodeCoverageTextMarker markerOne;
+ CodeCoverageTextMarker markerTwo;
+ CodeCoverageTextMarker markerThree;
+ MockDocument document;
+
+ [TestFixtureSetUp]
+ public void SetUpFixture()
+ {
+ try {
+ string configFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "NCoverAddIn.Tests");
+ PropertyService.InitializeService(configFolder, Path.Combine(configFolder, "data"), "NCoverAddIn.Tests");
+ } catch (Exception) {}
+
+ document = new MockDocument();
+ string code = "\t\t{\r\n" +
+ "\t\t\tint count = 0;\r\n" +
+ "\t\t}\r\n";
+ document.AddLines(code);
+ markerStrategy = new MarkerStrategy(document);
+
+ string xml = "\r\n" +
+ "\t\r\n" +
+ "\t\t\r\n" +
+ "\t\r\n" +
+ "";
+ CodeCoverageResults results = new CodeCoverageResults(new StringReader(xml));
+ CodeCoverageMethod method = results.Modules[0].Methods[0];
+ CodeCoverageHighlighter highlighter = new CodeCoverageHighlighter();
+ highlighter.AddMarkers(markerStrategy, method.SequencePoints);
+
+ foreach (CodeCoverageTextMarker marker in markerStrategy.TextMarker) {
+ if (markerOne == null) {
+ markerOne = marker;
+ } else if (markerTwo == null) {
+ markerTwo = marker;
+ } else if (markerThree == null) {
+ markerThree = marker;
+ }
+ }
+ }
+
+ [Test]
+ public void MarkerCount()
+ {
+ int count = 0;
+ foreach (CodeCoverageTextMarker marker in markerStrategy.TextMarker) {
+ count++;
+ }
+
+ Assert.AreEqual(3, count);
+ }
+
+ [Test]
+ public void MarkerOneOffset()
+ {
+ Assert.AreEqual(3, markerOne.Offset);
+ }
+
+ [Test]
+ public void MarkerOneLength()
+ {
+ Assert.AreEqual(1, markerOne.Length);
+ }
+
+ [Test]
+ public void MarkerOneType()
+ {
+ Assert.AreEqual(TextMarkerType.SolidBlock, markerOne.TextMarkerType);
+ }
+
+ [Test]
+ public void MarkerOneForeColor()
+ {
+ Assert.AreEqual(CodeCoverageOptions.VisitedForeColor, markerOne.ForeColor);
+ }
+
+ [Test]
+ public void MarkerOneColor()
+ {
+ Assert.AreEqual(CodeCoverageOptions.VisitedColor, markerOne.Color);
+ }
+
+ [Test]
+ public void MarkerTwoOffset()
+ {
+ Assert.AreEqual(9, markerTwo.Offset);
+ }
+
+ [Test]
+ public void MarkerTwoLength()
+ {
+ Assert.AreEqual(14, markerTwo.Length);
+ }
+
+ [Test]
+ public void MarkerThreeForeColor()
+ {
+ Assert.AreEqual(CodeCoverageOptions.NotVisitedForeColor, markerThree.ForeColor);
+ }
+
+ [Test]
+ public void MarkerThreeColor()
+ {
+ Assert.AreEqual(CodeCoverageOptions.NotVisitedColor, markerThree.Color);
+ }
+
+ [Test]
+ public void MarkerThreeOffset()
+ {
+ Assert.AreEqual(27, markerThree.Offset);
+ }
+
+ [Test]
+ public void MarkerThreeLength()
+ {
+ Assert.AreEqual(1, markerThree.Length);
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/AssemblyInfo.cs b/src/AddIns/Misc/CodeCoverage/Test/AssemblyInfo.cs
new file mode 100644
index 0000000000..906720da13
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/AssemblyInfo.cs
@@ -0,0 +1,27 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following
+// attributes.
+//
+// change them to the information which is associated with the assembly
+// you compile.
+
+[assembly: AssemblyTitle("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has following format :
+//
+// Major.Minor.Build.Revision
+//
+// You can specify all values by your own or you can build default build and revision
+// numbers with the '*' character (the default):
+
+[assembly: AssemblyVersion("1.0.*")]
+
diff --git a/src/AddIns/Misc/CodeCoverage/Test/CodeCoverage.Tests.csproj b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverage.Tests.csproj
new file mode 100644
index 0000000000..53ad7a1104
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverage.Tests.csproj
@@ -0,0 +1,83 @@
+
+
+ Library
+ ICSharpCode.CodeCoverage.Tests
+ CodeCoverage.Tests
+ Debug
+ AnyCPU
+ {A5C0E8F8-9D04-46ED-91D6-1DEF1575313B}
+ False
+ False
+ False
+ Auto
+ 4194304
+ AnyCPU
+ 4096
+ 4
+ false
+
+
+ ..\..\..\..\..\bin\UnitTests\
+ False
+ DEBUG;TRACE
+ true
+ Full
+ True
+
+
+ ..\..\..\..\..\bin\UnitTests\
+ True
+ TRACE
+ false
+ None
+ False
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {2748AD25-9C63-4E12-877B-4DCE96FBED54}
+ ICSharpCode.SharpDevelop
+
+
+ {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}
+ ICSharpCode.Core
+
+
+ {2D18BE89-D210-49EB-A9DD-2246FBB3DF6D}
+ ICSharpCode.TextEditor
+
+
+ {83DD7E12-A705-4DBA-9D71-09C8973D9382}
+ nunit.framework.dll
+
+
+ {B7F1A068-01F5-49E7-83EF-05DE281B09FD}
+ CodeCoverageAddIn
+
+
+
+
\ No newline at end of file
diff --git a/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersCoverMultipleLinesTestFixture.cs b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersCoverMultipleLinesTestFixture.cs
new file mode 100644
index 0000000000..58451f69b7
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersCoverMultipleLinesTestFixture.cs
@@ -0,0 +1,89 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.CodeCoverage;
+using ICSharpCode.TextEditor.Document;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace ICSharpCode.CodeCoverage.Tests
+{
+ [TestFixture]
+ public class CodeCoverageMarkersCoverMultipleLinesTestFixture
+ {
+ List markers;
+ [TestFixtureSetUp]
+ public void SetUpFixture()
+ {
+ try {
+ string configFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "NCoverAddIn.Tests");
+ PropertyService.InitializeService(configFolder, Path.Combine(configFolder, "data"), "NCoverAddIn.Tests");
+ } catch (Exception) {}
+
+ MockDocument document = new MockDocument();
+ string code = "\t\t{\r\n" +
+ "\t\t\treturn \"\\r\\n\" +\r\n" +
+ "\t\t\t\t\"\\r\\n\" +\r\n" +
+ "\t\t\t\t\"\\r\\n\" +\r\n" +
+ "\t\t\t\t\"\\r\\n\" +\r\n" +
+ "\t\t\t\t\"\";\r\n" +
+ "\t\t}\r\n";
+ document.AddLines(code);
+ MarkerStrategy markerStrategy = new MarkerStrategy(document);
+
+ string xml = "\r\n" +
+ "\t\r\n" +
+ "\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\r\n" +
+ "\t\r\n" +
+ "";
+
+ CodeCoverageResults results = new CodeCoverageResults(new StringReader(xml));
+ CodeCoverageMethod method = results.Modules[0].Methods[0];
+ CodeCoverageHighlighter highlighter = new CodeCoverageHighlighter();
+ highlighter.AddMarkers(markerStrategy, method.SequencePoints);
+
+ markers = new List();
+ foreach (CodeCoverageTextMarker marker in markerStrategy.TextMarker) {
+ markers.Add(marker);
+ }
+ }
+
+ [Test]
+ public void MarkerCount()
+ {
+ Assert.AreEqual(10, markers.Count);
+ }
+
+ [Test]
+ public void MarkerThreeOffset()
+ {
+ Assert.AreEqual(48, markers[2].Offset);
+ }
+
+ [Test]
+ public void MarkerFourOffset()
+ {
+ Assert.AreEqual(118, markers[3].Offset);
+ }
+
+ [Test]
+ public void MarkerNineOffset()
+ {
+ Assert.AreEqual(338, markers[8].Offset);
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersCoverTwoLinesTestFixture.cs b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersCoverTwoLinesTestFixture.cs
new file mode 100644
index 0000000000..2eedca5db3
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersCoverTwoLinesTestFixture.cs
@@ -0,0 +1,118 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.CodeCoverage;
+using ICSharpCode.TextEditor.Document;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace ICSharpCode.CodeCoverage.Tests
+{
+ [TestFixture]
+ public class CodeCoverageMarkersCoverTwoLinesTestFixture
+ {
+ CodeCoverageTextMarker markerOne;
+ CodeCoverageTextMarker markerTwo;
+ CodeCoverageTextMarker markerThree;
+ CodeCoverageTextMarker markerFour;
+
+ [TestFixtureSetUp]
+ public void SetUpFixture()
+ {
+ try {
+ string configFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "NCoverAddIn.Tests");
+ PropertyService.InitializeService(configFolder, Path.Combine(configFolder, "data"), "NCoverAddIn.Tests");
+ } catch (Exception) {}
+
+ MockDocument document = new MockDocument();
+ string code = "\t\t{\r\n" +
+ "\t\t\tAssert.AreEqual(0, childElementCompletionData.Length, \"\" +\r\n" +
+ "\t\t\t \"Not expecting any child elements.\");\r\n" +
+ "\t\t}\r\n";
+ document.AddLines(code);
+ MarkerStrategy markerStrategy = new MarkerStrategy(document);
+
+ string xml = "\r\n" +
+ "\t\r\n" +
+ "\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\r\n" +
+ "\t\r\n" +
+ "";
+
+ CodeCoverageResults results = new CodeCoverageResults(new StringReader(xml));
+ CodeCoverageMethod method = results.Modules[0].Methods[0];
+ CodeCoverageHighlighter highlighter = new CodeCoverageHighlighter();
+ highlighter.AddMarkers(markerStrategy, method.SequencePoints);
+
+ foreach (CodeCoverageTextMarker marker in markerStrategy.TextMarker) {
+ if (markerOne == null) {
+ markerOne = marker;
+ } else if (markerTwo == null) {
+ markerTwo = marker;
+ } else if (markerThree == null) {
+ markerThree = marker;
+ } else if (markerFour == null) {
+ markerFour = marker;
+ }
+ }
+ }
+
+ [Test]
+ public void MarkerOneOffset()
+ {
+ Assert.AreEqual(3, markerOne.Offset);
+ }
+
+ [Test]
+ public void MarkerOneLength()
+ {
+ Assert.AreEqual(1, markerOne.Length);
+ }
+
+ [Test]
+ public void MarkerTwoOffset()
+ {
+ Assert.AreEqual(9, markerTwo.Offset);
+ }
+
+ [Test]
+ public void MarkerTwoLength()
+ {
+ Assert.AreEqual(56, markerTwo.Length);
+ }
+
+ [Test]
+ public void MarkerThreeOffset()
+ {
+ Assert.AreEqual(68, markerThree.Offset);
+ }
+
+ [Test]
+ public void MarkerThreeLength()
+ {
+ Assert.AreEqual(56, markerThree.Length);
+ }
+
+ [Test]
+ public void MarkerFourLength()
+ {
+ Assert.AreEqual(1, markerFour.Length);
+ }
+
+ [Test]
+ public void MarkerFourOffset()
+ {
+ Assert.AreEqual(129, markerFour.Offset);
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersInvalidEndColumnTestFixture.cs b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersInvalidEndColumnTestFixture.cs
new file mode 100644
index 0000000000..b87d9796af
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersInvalidEndColumnTestFixture.cs
@@ -0,0 +1,64 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.CodeCoverage;
+using ICSharpCode.TextEditor.Document;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace ICSharpCode.CodeCoverage.Tests
+{
+ [TestFixture]
+ public class CodeCoverageMarkersInvalidEndColumnTestFixture
+ {
+ List markers;
+
+ [SetUp]
+ public void Init()
+ {
+ try {
+ string configFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "NCoverAddIn.Tests");
+ PropertyService.InitializeService(configFolder, Path.Combine(configFolder, "data"), "NCoverAddIn.Tests");
+ } catch (Exception) {}
+
+ MockDocument document = new MockDocument();
+ document.AddLines("abcdefg\r\nabc");
+ MarkerStrategy markerStrategy = new MarkerStrategy(document);
+
+ string xml = "\r\n" +
+ "\t\r\n" +
+ "\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\r\n" +
+ "\t\r\n" +
+ "";
+
+ CodeCoverageResults results = new CodeCoverageResults(new StringReader(xml));
+ CodeCoverageMethod method = results.Modules[0].Methods[0];
+ CodeCoverageHighlighter highlighter = new CodeCoverageHighlighter();
+ highlighter.AddMarkers(markerStrategy, method.SequencePoints);
+
+ markers = new List();
+ foreach (CodeCoverageTextMarker marker in markerStrategy.TextMarker) {
+ markers.Add(marker);
+ }
+ }
+
+ [Test]
+ public void NoMarkersAdded()
+ {
+ Assert.AreEqual(0, markers.Count,
+ "Should not be any markers added since all sequence point end columns are invalid.");
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersInvalidEndLineTestFixture.cs b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersInvalidEndLineTestFixture.cs
new file mode 100644
index 0000000000..ffa7271f83
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersInvalidEndLineTestFixture.cs
@@ -0,0 +1,65 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.CodeCoverage;
+using ICSharpCode.TextEditor.Document;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace ICSharpCode.CodeCoverage.Tests
+{
+ [TestFixture]
+ public class CodeCoverageMarkersInvalidEndLineTestFixture
+ {
+ List markers;
+
+ [SetUp]
+ public void Init()
+ {
+ try {
+ string configFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "NCoverAddIn.Tests");
+ PropertyService.InitializeService(configFolder, Path.Combine(configFolder, "data"), "NCoverAddIn.Tests");
+ } catch (Exception) {}
+
+ MockDocument document = new MockDocument();
+ // Give doc 3 lines (end line seems to be counted as an extra line).
+ document.AddLines("abc\r\ndef");
+ MarkerStrategy markerStrategy = new MarkerStrategy(document);
+
+ string xml = "\r\n" +
+ "\t\r\n" +
+ "\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\r\n" +
+ "\t\r\n" +
+ "";
+
+ CodeCoverageResults results = new CodeCoverageResults(new StringReader(xml));
+ CodeCoverageMethod method = results.Modules[0].Methods[0];
+ CodeCoverageHighlighter highlighter = new CodeCoverageHighlighter();
+ highlighter.AddMarkers(markerStrategy, method.SequencePoints);
+
+ markers = new List();
+ foreach (CodeCoverageTextMarker marker in markerStrategy.TextMarker) {
+ markers.Add(marker);
+ }
+ }
+
+ [Test]
+ public void NoMarkersAdded()
+ {
+ Assert.AreEqual(0, markers.Count,
+ "Should not be any markers added since all sequence point end lines are invalid.");
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersInvalidStartColumnTestFixture.cs b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersInvalidStartColumnTestFixture.cs
new file mode 100644
index 0000000000..3289b27af3
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersInvalidStartColumnTestFixture.cs
@@ -0,0 +1,63 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.CodeCoverage;
+using ICSharpCode.TextEditor.Document;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace ICSharpCode.CodeCoverage.Tests
+{
+ [TestFixture]
+ public class CodeCoverageMarkersInvalidStartColumnTestFixture
+ {
+ List markers;
+
+ [SetUp]
+ public void Init()
+ {
+ try {
+ string configFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "NCoverAddIn.Tests");
+ PropertyService.InitializeService(configFolder, Path.Combine(configFolder, "data"), "NCoverAddIn.Tests");
+ } catch (Exception) {}
+
+ MockDocument document = new MockDocument();
+ document.AddLines("abcdefg\r\nabcdefg");
+ MarkerStrategy markerStrategy = new MarkerStrategy(document);
+
+ string xml = "\r\n" +
+ "\t\r\n" +
+ "\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\r\n" +
+ "\t\r\n" +
+ "";
+
+ CodeCoverageResults results = new CodeCoverageResults(new StringReader(xml));
+ CodeCoverageMethod method = results.Modules[0].Methods[0];
+ CodeCoverageHighlighter highlighter = new CodeCoverageHighlighter();
+ highlighter.AddMarkers(markerStrategy, method.SequencePoints);
+
+ markers = new List();
+ foreach (CodeCoverageTextMarker marker in markerStrategy.TextMarker) {
+ markers.Add(marker);
+ }
+ }
+
+ [Test]
+ public void NoMarkersAdded()
+ {
+ Assert.AreEqual(0, markers.Count,
+ "Should not be any markers added since all sequence point start columns are invalid.");
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersInvalidStartLineTestFixture.cs b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersInvalidStartLineTestFixture.cs
new file mode 100644
index 0000000000..37d8e004e5
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageMarkersInvalidStartLineTestFixture.cs
@@ -0,0 +1,62 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.CodeCoverage;
+using ICSharpCode.TextEditor.Document;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace ICSharpCode.CodeCoverage.Tests
+{
+ [TestFixture]
+ public class CodeCoverageMarkersInvalidStartLineTestFixture
+ {
+ List markers;
+
+ [SetUp]
+ public void Init()
+ {
+ try {
+ string configFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "NCoverAddIn.Tests");
+ PropertyService.InitializeService(configFolder, Path.Combine(configFolder, "data"), "NCoverAddIn.Tests");
+ } catch (Exception) {}
+
+ MockDocument document = new MockDocument();
+ MarkerStrategy markerStrategy = new MarkerStrategy(document);
+
+ string xml = "\r\n" +
+ "\t\r\n" +
+ "\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\r\n" +
+ "\t\r\n" +
+ "";
+
+ CodeCoverageResults results = new CodeCoverageResults(new StringReader(xml));
+ CodeCoverageMethod method = results.Modules[0].Methods[0];
+ CodeCoverageHighlighter highlighter = new CodeCoverageHighlighter();
+ highlighter.AddMarkers(markerStrategy, method.SequencePoints);
+
+ markers = new List();
+ foreach (CodeCoverageTextMarker marker in markerStrategy.TextMarker) {
+ markers.Add(marker);
+ }
+ }
+
+ [Test]
+ public void NoMarkersAdded()
+ {
+ Assert.AreEqual(0, markers.Count,
+ "Should not be any markers added since all sequence point start lines are invalid.");
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageResultsTestFixture.cs b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageResultsTestFixture.cs
new file mode 100644
index 0000000000..2612745ea9
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageResultsTestFixture.cs
@@ -0,0 +1,148 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.CodeCoverage;
+using NUnit.Framework;
+using System;
+using System.IO;
+
+namespace ICSharpCode.CodeCoverage.Tests
+{
+ [TestFixture]
+ public class CodeCoverageResultsTestFixture
+ {
+ CodeCoverageModule module;
+ CodeCoverageResults results;
+ CodeCoverageMethod method;
+ CodeCoverageSequencePoint point1;
+ CodeCoverageSequencePoint point2;
+ CodeCoverageSequencePoint point3;
+
+ [TestFixtureSetUp]
+ public void SetUpFixture()
+ {
+ string xml = "\r\n" +
+ "\t\r\n" +
+ "\t\t\r\n" +
+ "\t\r\n" +
+ "";
+ results = new CodeCoverageResults(new StringReader(xml));
+ module = results.Modules[0];
+ method = module.Methods[0];
+
+ point1 = method.SequencePoints[0];
+ point2 = method.SequencePoints[1];
+ point3 = method.SequencePoints[2];
+ }
+
+ [Test]
+ public void AssemblyName()
+ {
+ Assert.AreEqual("Foo.Tests", module.Name);
+ }
+
+ [Test]
+ public void ModuleCount()
+ {
+ Assert.AreEqual(1, results.Modules.Count);
+ }
+
+ [Test]
+ public void MethodCount()
+ {
+ Assert.AreEqual(1, module.Methods.Count);
+ }
+
+ [Test]
+ public void MethodName()
+ {
+ Assert.AreEqual("SimpleTest", method.Name);
+ }
+
+ [Test]
+ public void FullClassName()
+ {
+ Assert.AreEqual("Foo.Tests.FooTestFixture", method.FullClassName);
+ }
+
+ [Test]
+ public void ClassName()
+ {
+ Assert.AreEqual("FooTestFixture", method.ClassName);
+ }
+
+ [Test]
+ public void ClassNamespace()
+ {
+ Assert.AreEqual("Foo.Tests", method.ClassNamespace);
+ }
+
+ [Test]
+ public void SequencePointCount()
+ {
+ Assert.AreEqual(3, method.SequencePoints.Count);
+ }
+
+ [Test]
+ public void SequencePointDocument()
+ {
+ Assert.AreEqual("c:\\Projects\\Foo\\FooTestFixture.cs", point1.Document);
+ }
+
+ [Test]
+ public void SequencePoint1VisitCount()
+ {
+ Assert.AreEqual(1, point1.VisitCount);
+ }
+
+ [Test]
+ public void SequencePoint3VisitCount()
+ {
+ Assert.AreEqual(0, point3.VisitCount);
+ }
+
+ [Test]
+ public void SequencePoint1Line()
+ {
+ Assert.AreEqual(20, point1.Line);
+ }
+
+ [Test]
+ public void SequencePoint1Column()
+ {
+ Assert.AreEqual(3, point1.Column);
+ }
+
+ [Test]
+ public void SequencePoint1EndLine()
+ {
+ Assert.AreEqual(20, point1.EndLine);
+ }
+
+ [Test]
+ public void SequencePoint1EndColumn()
+ {
+ Assert.AreEqual(4, point1.EndColumn);
+ }
+
+ [Test]
+ public void MethodVisitedCount()
+ {
+ Assert.AreEqual(2, method.VisitedSequencePointsCount);
+ }
+
+ [Test]
+ public void MethodNotVisitedCount()
+ {
+ Assert.AreEqual(1, method.NotVisitedSequencePointsCount);
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageTreeViewTestFixture.cs b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageTreeViewTestFixture.cs
new file mode 100644
index 0000000000..648ba8bf98
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/CodeCoverageTreeViewTestFixture.cs
@@ -0,0 +1,166 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.SharpDevelop.Gui;
+using ICSharpCode.CodeCoverage;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+
+namespace ICSharpCode.CodeCoverage.Tests
+{
+ [TestFixture]
+ public class CodeCoverageTreeViewTestFixture
+ {
+ TreeNodeCollection nodes;
+ CodeCoverageModuleTreeNode fooModuleNode;
+ CodeCoverageModuleTreeNode barModuleNode;
+ CodeCoverageClassTreeNode class1TreeNode;
+ CodeCoverageMethodTreeNode method1TreeNode;
+ CodeCoverageMethodTreeNode method2TreeNode;
+ CodeCoverageNamespaceTreeNode namespace1TreeNode;
+ CodeCoverageNamespaceTreeNode namespace2TreeNode;
+
+ [TestFixtureSetUp]
+ public void SetUpFixture()
+ {
+ List modules = new List();
+ CodeCoverageModule m1 = new CodeCoverageModule("Foo.Tests");
+ CodeCoverageMethod method1 = new CodeCoverageMethod("Test1", "Foo.Tests.TestFixture1");
+ method1.SequencePoints.Add(new CodeCoverageSequencePoint("c:\\Projects\\Foo\\TestFixture1.cs", 1, 1, 0, 2, 1));
+ method1.SequencePoints.Add(new CodeCoverageSequencePoint("c:\\Projects\\Foo\\TestFixture1.cs", 0, 2, 2, 3, 4));
+ CodeCoverageMethod method2 = new CodeCoverageMethod("Test2", "Foo.Tests.TestFixture1");
+
+ m1.Methods.Add(method1);
+ m1.Methods.Add(method2);
+
+ CodeCoverageModule m2 = new CodeCoverageModule("Bar.Tests");
+
+ modules.Add(m1);
+ modules.Add(m2);
+
+ using (CodeCoverageTreeView treeView = new CodeCoverageTreeView()) {
+ treeView.AddModules(modules);
+ treeView.ExpandAll();
+ nodes = treeView.Nodes;
+ }
+
+ fooModuleNode = (CodeCoverageModuleTreeNode)nodes[0];
+ barModuleNode = (CodeCoverageModuleTreeNode)nodes[1];
+
+ namespace1TreeNode = (CodeCoverageNamespaceTreeNode)fooModuleNode.Nodes[0];
+ namespace2TreeNode = (CodeCoverageNamespaceTreeNode)namespace1TreeNode.Nodes[0];
+
+ class1TreeNode = (CodeCoverageClassTreeNode)namespace2TreeNode.Nodes[0];
+ method1TreeNode = (CodeCoverageMethodTreeNode)class1TreeNode.Nodes[0];
+ method2TreeNode = (CodeCoverageMethodTreeNode)class1TreeNode.Nodes[1];
+ }
+
+ [Test]
+ public void RootNodesCount()
+ {
+ Assert.AreEqual(2, nodes.Count);
+ }
+
+ [Test]
+ public void FooModuleTreeNodeText()
+ {
+ Assert.AreEqual("Foo.Tests (50%)", fooModuleNode.Text);
+ }
+
+ [Test]
+ public void FooModuleTreeNodeForeColor()
+ {
+ Assert.AreEqual(CodeCoverageTreeNode.PartialCoverageTextColor, fooModuleNode.ForeColor);
+ }
+
+ [Test]
+ public void FooModuleChildNodesCount()
+ {
+ Assert.AreEqual(1, fooModuleNode.Nodes.Count);
+ }
+
+ [Test]
+ public void FooModuleTreeNodeName()
+ {
+ Assert.AreEqual("Foo.Tests", fooModuleNode.Name);
+ }
+
+ [Test]
+ public void BarModuleTreeNodeText()
+ {
+ Assert.AreEqual("Bar.Tests", barModuleNode.Text);
+ }
+
+ [Test]
+ public void Class1TreeNodeName()
+ {
+ Assert.AreEqual("TestFixture1", class1TreeNode.Name);
+ }
+
+ [Test]
+ public void Class1TreeNodeText()
+ {
+ Assert.AreEqual("TestFixture1 (50%)", class1TreeNode.Text);
+ }
+
+ [Test]
+ public void Namespace1TreeNodeName()
+ {
+ Assert.AreEqual("Foo", namespace1TreeNode.Name);
+ }
+
+ [Test]
+ public void Namespace2TreeNodeName()
+ {
+ Assert.AreEqual("Tests", namespace2TreeNode.Name);
+ }
+
+ [Test]
+ public void Namespace1TreeNodeText()
+ {
+ Assert.AreEqual("Foo (50%)", namespace1TreeNode.Text);
+ }
+
+ [Test]
+ public void Namespace2TreeNodeText()
+ {
+ Assert.AreEqual("Tests (50%)", namespace2TreeNode.Text);
+ }
+
+ [Test]
+ public void Method1TreeNodeName()
+ {
+ Assert.AreEqual("Test1", method1TreeNode.Name);
+ }
+
+ [Test]
+ public void Method1TreeNodeText()
+ {
+ Assert.AreEqual("Test1 (50%)", method1TreeNode.Text);
+ }
+
+ [Test]
+ public void Method2TreeNodeText()
+ {
+ Assert.AreEqual("Test2", method2TreeNode.Name);
+ }
+
+ [Test]
+ public void Class1TreeNodeChildNodesCount()
+ {
+ Assert.AreEqual(2, class1TreeNode.Nodes.Count);
+ }
+
+ [Test]
+ public void Namespace2TreeNodeChildNodesCount()
+ {
+ Assert.AreEqual(1, namespace2TreeNode.Nodes.Count);
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/GetSequencePointsForFileNameTestFixture.cs b/src/AddIns/Misc/CodeCoverage/Test/GetSequencePointsForFileNameTestFixture.cs
new file mode 100644
index 0000000000..76d9a40a4f
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/GetSequencePointsForFileNameTestFixture.cs
@@ -0,0 +1,78 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.CodeCoverage;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace ICSharpCode.CodeCoverage.Tests
+{
+ [TestFixture]
+ public class GetSequencePointsForFileNameTestFixture
+ {
+ CodeCoverageResults results;
+ List fooTestFixtureSequencePoints;
+ List barTestFixtureSequencePoints;
+ List simpleTestFixtureSequencePoints;
+ List nonExistentFileNameSequencePoints;
+
+ [SetUp]
+ public void SetUpFixture()
+ {
+ string xml = "\r\n" +
+ "\t\r\n" +
+ "\t\t\r\n" +
+ "\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\r\n" +
+ "\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\r\n" +
+ "\t\r\n" +
+ "\t\r\n" +
+ "\t\t\r\n" +
+ "\t\t\t\r\n" +
+ "\t\t\r\n" +
+ "\t\r\n" +
+ "";
+
+ results = new CodeCoverageResults(new StringReader(xml));
+ fooTestFixtureSequencePoints = results.GetSequencePoints(@"c:\Projects\Foo\FooTestFixture.cs");
+ barTestFixtureSequencePoints = results.GetSequencePoints(@"c:\Projects\Foo\BarTestFixture.cs");
+ simpleTestFixtureSequencePoints = results.GetSequencePoints(@"c:\Projects\Foo\SimpleTestFixture.cs");
+ nonExistentFileNameSequencePoints = results.GetSequencePoints(@"c:\Projects\Foo\NoSuchTestFixture.cs");
+ }
+
+ [Test]
+ public void FooTestFixtureHasSequencePoint()
+ {
+ Assert.AreEqual(1, fooTestFixtureSequencePoints.Count);
+ }
+
+ [Test]
+ public void BarTestFixtureHasSequencePoint()
+ {
+ Assert.AreEqual(1, barTestFixtureSequencePoints.Count);
+ }
+
+ [Test]
+ public void SimpleTestFixtureHasSequencePoints()
+ {
+ Assert.AreEqual(2, simpleTestFixtureSequencePoints.Count);
+ }
+
+ [Test]
+ public void NonExistentFileNameHasNoSequencePoints()
+ {
+ Assert.AreEqual(0, nonExistentFileNameSequencePoints.Count);
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/MbUnitResultsTestFixture.cs b/src/AddIns/Misc/CodeCoverage/Test/MbUnitResultsTestFixture.cs
new file mode 100644
index 0000000000..c3c88e051e
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/MbUnitResultsTestFixture.cs
@@ -0,0 +1,121 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.CodeCoverage;
+using NUnit.Framework;
+using System;
+using System.IO;
+using System.Resources;
+
+namespace ICSharpCode.CodeCoverage.Tests
+{
+ [TestFixture]
+ public class MbUnitResultsTestFixture
+ {
+ Task errorTask;
+
+ [SetUp]
+ public void Init()
+ {
+ // Add NUnitPad TestFailedMessage string resource since this resource
+ // contains a format string that has parameters that are otherwise not
+ // set.
+ ResourceManager resourceManager = new ResourceManager("ICSharpCode.CodeCoverage.Tests.Strings", GetType().Assembly);
+ ResourceService.RegisterNeutralStrings(resourceManager);
+
+ MbUnitResults results = new MbUnitResults(new StringReader(GetMbUnitResultsXml()));
+ errorTask = results.Tasks[0];
+ }
+
+ [Test]
+ public void IsErrorTask()
+ {
+ Assert.AreEqual(TaskType.Error, errorTask.TaskType);
+ }
+
+ [Test]
+ public void ErrorTaskFileName()
+ {
+ Assert.IsTrue(FileUtility.IsEqualFileName(@"c:\test\NunitFoo\NunitFoo.Tests\FooTest.cs", errorTask.FileName));
+ }
+
+ [Test]
+ public void ErrorTaskLine()
+ {
+ Assert.AreEqual(21, errorTask.Line);
+ }
+
+ [Test]
+ public void ErrorTaskColumn()
+ {
+ Assert.AreEqual(0, errorTask.Column);
+ }
+
+ [Test]
+ public void TaskDescription()
+ {
+ string description = StringParser.Parse("${res:NUnitPad.NUnitPadContent.TestTreeView.TestFailedMessage}", new string[,] {
+ {"TestCase", "FooTest.Foo"},
+ {"Message", "Foo failed"}
+ });
+
+ Assert.AreEqual(description, errorTask.Description);
+ }
+
+ string GetMbUnitResultsXml()
+ {
+ return "\r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " Foo failed\r\n" +
+ " nunit.framework\r\n" +
+ " at NUnit.Framework.Assert.Fail(String message, Object[] args)\r\n" +
+ " at NUnit.Framework.Assert.Fail(String message)\r\n" +
+ " at NunitFoo.Tests.FooTest.Foo() in c:\\test\\NunitFoo\\NunitFoo.Tests\\FooTest.cs:line 22\r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ "";
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/MockDocument.cs b/src/AddIns/Misc/CodeCoverage/Test/MockDocument.cs
new file mode 100644
index 0000000000..c05c41ce81
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/MockDocument.cs
@@ -0,0 +1,276 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.TextEditor.Document;
+using System;
+using System.Collections.Generic;
+
+namespace ICSharpCode.CodeCoverage.Tests
+{
+ ///
+ /// Helper class that implements the Text Editor library's IDocument interface.
+ ///
+ public class MockDocument : IDocument
+ {
+ List lineSegments = new List();
+
+ public MockDocument()
+ {
+ }
+
+ public event EventHandler UpdateCommited;
+
+ public event DocumentEventHandler DocumentAboutToBeChanged;
+
+ public event DocumentEventHandler DocumentChanged;
+
+ public event EventHandler TextContentChanged;
+
+ public void AddLines(string code)
+ {
+ int offset = 0;
+ string[] lines = code.Split('\n');
+ foreach (string line in lines) {
+ int delimiterLength = 1;
+ if (line.Length > 0 && line[line.Length - 1] == '\r') {
+ delimiterLength = 2;
+ }
+ LineSegment lineSegment = new LineSegment(offset, offset + line.Length, delimiterLength);
+ lineSegments.Add(lineSegment);
+ offset += line.Length + lineSegment.DelimiterLength - 1;
+ }
+ }
+
+ public ITextEditorProperties TextEditorProperties {
+ get {
+ throw new NotImplementedException();
+ }
+ set {
+ throw new NotImplementedException();
+ }
+ }
+
+ public ICSharpCode.TextEditor.Undo.UndoStack UndoStack {
+ get {
+ throw new NotImplementedException();
+ }
+ }
+
+ public bool ReadOnly {
+ get {
+ throw new NotImplementedException();
+ }
+ set {
+ throw new NotImplementedException();
+ }
+ }
+
+ public IFormattingStrategy FormattingStrategy {
+ get {
+ throw new NotImplementedException();
+ }
+ set {
+ throw new NotImplementedException();
+ }
+ }
+
+ public ITextBufferStrategy TextBufferStrategy {
+ get {
+ throw new NotImplementedException();
+ }
+ }
+
+ public FoldingManager FoldingManager {
+ get {
+ throw new NotImplementedException();
+ }
+ }
+
+ public IHighlightingStrategy HighlightingStrategy {
+ get {
+ throw new NotImplementedException();
+ }
+ set {
+ throw new NotImplementedException();
+ }
+ }
+
+ public BookmarkManager BookmarkManager {
+ get {
+ throw new NotImplementedException();
+ }
+ }
+
+ public ICustomLineManager CustomLineManager {
+ get {
+ throw new NotImplementedException();
+ }
+ }
+
+ public MarkerStrategy MarkerStrategy {
+ get {
+ throw new NotImplementedException();
+ }
+ }
+
+ public System.Collections.Generic.List LineSegmentCollection {
+ get {
+ return lineSegments;
+ }
+ }
+
+ public int TotalNumberOfLines {
+ get {
+ if (lineSegments.Count == 0) {
+ return 1;
+ }
+
+ return ((LineSegment)lineSegments[lineSegments.Count - 1]).DelimiterLength > 0 ? lineSegments.Count + 1 : lineSegments.Count;
+ }
+ }
+
+ public string TextContent {
+ get {
+ throw new NotImplementedException();
+ }
+ set {
+ throw new NotImplementedException();
+ }
+ }
+
+ public int TextLength {
+ get {
+ throw new NotImplementedException();
+ }
+ }
+
+ public System.Collections.Generic.List UpdateQueue {
+ get {
+ throw new NotImplementedException();
+ }
+ }
+
+ public void UpdateSegmentListOnDocumentChange(System.Collections.Generic.List list, DocumentEventArgs e) where T : ISegment
+ {
+ throw new NotImplementedException();
+ }
+
+ public int GetLineNumberForOffset(int offset)
+ {
+ throw new NotImplementedException();
+ }
+
+ public LineSegment GetLineSegmentForOffset(int offset)
+ {
+ throw new NotImplementedException();
+ }
+
+ public LineSegment GetLineSegment(int lineNumber)
+ {
+ return lineSegments[lineNumber];
+ }
+
+ public int GetFirstLogicalLine(int lineNumber)
+ {
+ throw new NotImplementedException();
+ }
+
+ public int GetLastLogicalLine(int lineNumber)
+ {
+ throw new NotImplementedException();
+ }
+
+ public int GetVisibleLine(int lineNumber)
+ {
+ throw new NotImplementedException();
+ }
+
+ public int GetNextVisibleLineAbove(int lineNumber, int lineCount)
+ {
+ throw new NotImplementedException();
+ }
+
+ public int GetNextVisibleLineBelow(int lineNumber, int lineCount)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Insert(int offset, string text)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Remove(int offset, int length)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Replace(int offset, int length, string text)
+ {
+ throw new NotImplementedException();
+ }
+
+ public char GetCharAt(int offset)
+ {
+ throw new NotImplementedException();
+ }
+
+ public string GetText(int offset, int length)
+ {
+ throw new NotImplementedException();
+ }
+
+ public string GetText(ISegment segment)
+ {
+ throw new NotImplementedException();
+ }
+
+ public System.Drawing.Point OffsetToPosition(int offset)
+ {
+ throw new NotImplementedException();
+ }
+
+ public int PositionToOffset(System.Drawing.Point p)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void RequestUpdate(ICSharpCode.TextEditor.TextAreaUpdate update)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void CommitUpdate()
+ {
+ throw new NotImplementedException();
+ }
+
+ void OnUpdateCommited()
+ {
+ if (UpdateCommited != null) {
+ }
+ }
+
+ void OnDocumentAboutToBeChanged()
+ {
+ if (DocumentAboutToBeChanged != null) {
+ }
+ }
+
+ void OnDocumentChanged()
+ {
+ if (DocumentChanged != null) {
+ }
+ }
+
+ void OnTextContentChanged()
+ {
+ if (TextContentChanged != null) {
+ }
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/ModuleVisitedSequencePointsTestFixture.cs b/src/AddIns/Misc/CodeCoverage/Test/ModuleVisitedSequencePointsTestFixture.cs
new file mode 100644
index 0000000000..566cb720a1
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/ModuleVisitedSequencePointsTestFixture.cs
@@ -0,0 +1,75 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.CodeCoverage;
+using NUnit.Framework;
+using System;
+using System.IO;
+
+namespace ICSharpCode.CodeCoverage.Tests
+{
+ [TestFixture]
+ public class ModuleVisitedSequencePointsTestFixture
+ {
+ CodeCoverageModule fooModule;
+ CodeCoverageModule barModule;
+ CodeCoverageResults results;
+
+ [TestFixtureSetUp]
+ public void SetUpFixture()
+ {
+ string xml = "\r\n" +
+ "\t\r\n" +
+ "\t\t\r\n" +
+ "\t\t\r\n" +
+ "\t\r\n" +
+ "\t\r\n" +
+ "\t\t\r\n" +
+ "\t\r\n" +
+ "";
+ results = new CodeCoverageResults(new StringReader(xml));
+ fooModule = results.Modules[0];
+ barModule = results.Modules[1];
+ }
+
+ [Test]
+ public void FooModuleVisitedCount()
+ {
+ Assert.AreEqual(4, fooModule.VisitedSequencePointsCount);
+ }
+
+ [Test]
+ public void FooModuleNotVisitedCount()
+ {
+ Assert.AreEqual(2, fooModule.NotVisitedSequencePointsCount);
+ }
+
+ [Test]
+ public void BarModuleVisitedCount()
+ {
+ Assert.AreEqual(2, barModule.VisitedSequencePointsCount);
+ }
+
+ [Test]
+ public void BarModuleNotVisitedCount()
+ {
+ Assert.AreEqual(1, barModule.NotVisitedSequencePointsCount);
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/NCoverSettingsTestFixture.cs b/src/AddIns/Misc/CodeCoverage/Test/NCoverSettingsTestFixture.cs
new file mode 100644
index 0000000000..1f4fa44821
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/NCoverSettingsTestFixture.cs
@@ -0,0 +1,49 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.CodeCoverage;
+using ICSharpCode.Core;
+using ICSharpCode.SharpDevelop.Project;
+using NUnit.Framework;
+using System;
+using System.IO;
+using System.Text;
+
+namespace ICSharpCode.CodeCoverage.Tests
+{
+ [TestFixture]
+ public class NCoverSettingsTestFixture
+ {
+ NCoverSettings settings;
+ NCoverSettings savedSettings;
+
+ [SetUp]
+ public void Init()
+ {
+ settings = new NCoverSettings();
+ settings.AssemblyList = "MyNamespace.Foo; MyNamespace.Bar";
+ StringBuilder savedSettingsXml = new StringBuilder();
+ settings.Save(new StringWriter(savedSettingsXml));
+ savedSettings = new NCoverSettings(new StringReader(savedSettingsXml.ToString()));
+ }
+
+ [Test]
+ public void IsAssemblyListSaved()
+ {
+ Assert.AreEqual(settings.AssemblyList, savedSettings.AssemblyList);
+ }
+
+ [Test]
+ public void NCoverSettingsFileName()
+ {
+ MSBuildProject project = new MSBuildProject();
+ project.FileName = @"C:\temp\test.csproj";
+
+ Assert.AreEqual(@"C:\temp\test.NCover.Settings", NCoverSettings.GetFileName(project));
+ }
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/RemoveCodeCoverageMarkersTestFixture.cs b/src/AddIns/Misc/CodeCoverage/Test/RemoveCodeCoverageMarkersTestFixture.cs
new file mode 100644
index 0000000000..5c58d56013
--- /dev/null
+++ b/src/AddIns/Misc/CodeCoverage/Test/RemoveCodeCoverageMarkersTestFixture.cs
@@ -0,0 +1,97 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.Core;
+using ICSharpCode.CodeCoverage;
+using ICSharpCode.TextEditor.Document;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace ICSharpCode.CodeCoverage.Tests
+{
+ [TestFixture]
+ public class RemoveCodeCoverageMarkersTestFixture
+ {
+ MarkerStrategy markerStrategy;
+
+ [TestFixtureSetUp]
+ public void SetUpTestFixture()
+ {
+ try {
+ string configFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "NCoverAddIn.Tests");
+ PropertyService.InitializeService(configFolder, Path.Combine(configFolder, "data"), "NCoverAddIn.Tests");
+ } catch (Exception) {}
+
+ MockDocument document = new MockDocument();
+ string code = "\t\t{\r\n" +
+ "\t\t\tint count = 0;\r\n" +
+ "\t\t}\r\n";
+ document.AddLines(code);
+ markerStrategy = new MarkerStrategy(document);
+
+ string xml = "\r\n" +
+ "\t\r\n" +
+ "\t\t\r\n" +
+ "\t\r\n" +
+ "";
+ CodeCoverageResults results = new CodeCoverageResults(new StringReader(xml));
+ CodeCoverageMethod method = results.Modules[0].Methods[0];
+ CodeCoverageHighlighter highlighter = new CodeCoverageHighlighter();
+ highlighter.AddMarkers(markerStrategy, method.SequencePoints);
+
+ // Add non-code coverage markers.
+ markerStrategy.AddMarker(new TextMarker(0, 2, TextMarkerType.Underlined));
+ markerStrategy.AddMarker(new TextMarker(4, 5, TextMarkerType.Underlined));
+ }
+
+ [Test]
+ public void RemoveCodeCoverageMarkers()
+ {
+ // Check that code coverage markers exist.
+ Assert.IsTrue(ContainsCodeCoverageMarkers(markerStrategy));
+
+ // Remove code coverage markers.
+ CodeCoverageHighlighter highlighter = new CodeCoverageHighlighter();
+ highlighter.RemoveMarkers(markerStrategy);
+
+ // Check that code coverage markers have been removed.
+ Assert.IsFalse(ContainsCodeCoverageMarkers(markerStrategy));
+
+ // Check that non-code coverage markers still exist.
+ Assert.IsTrue(ContainsNonCodeCoverageMarkers(markerStrategy));
+ }
+
+ static bool ContainsCodeCoverageMarkers(MarkerStrategy markerStrategy)
+ {
+ foreach (TextMarker marker in markerStrategy.TextMarker) {
+ if (marker is CodeCoverageTextMarker) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static bool ContainsNonCodeCoverageMarkers(MarkerStrategy markerStrategy)
+ {
+ int count = 0;
+ foreach (TextMarker marker in markerStrategy.TextMarker) {
+ if (marker is CodeCoverageTextMarker) {
+ return false;
+ }
+ count++;
+ }
+ return count > 0;
+ }
+
+ }
+}
diff --git a/src/AddIns/Misc/CodeCoverage/Test/Strings.resources b/src/AddIns/Misc/CodeCoverage/Test/Strings.resources
new file mode 100644
index 0000000000..33d565fcc1
Binary files /dev/null and b/src/AddIns/Misc/CodeCoverage/Test/Strings.resources differ
diff --git a/src/AddIns/Misc/MbUnitPad/MbUnitPad.sln b/src/AddIns/Misc/MbUnitPad/MbUnitPad.sln
index 6cd0ab4f09..1f592ebc2c 100644
--- a/src/AddIns/Misc/MbUnitPad/MbUnitPad.sln
+++ b/src/AddIns/Misc/MbUnitPad/MbUnitPad.sln
@@ -1,6 +1,16 @@
-Microsoft Visual Studio Solution File, Format Version 9.00
-# SharpDevelop 2.0.0.339
+Microsoft Visual Studio Solution File, Format Version 9.00
+# SharpDevelop 2.0.0.960
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MbUnitPad", "Project\MbUnitPad.csproj", "{B1CE28A0-04E8-490D-8256-E0C4D52C93C8}"
EndProject
Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B1CE28A0-04E8-490D-8256-E0C4D52C93C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B1CE28A0-04E8-490D-8256-E0C4D52C93C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B1CE28A0-04E8-490D-8256-E0C4D52C93C8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B1CE28A0-04E8-490D-8256-E0C4D52C93C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ EndGlobalSection
EndGlobal
diff --git a/src/AddIns/Misc/MbUnitPad/Project/Src/MbUnitPad.cs b/src/AddIns/Misc/MbUnitPad/Project/Src/MbUnitPad.cs
index a2161205fc..610b152e15 100644
--- a/src/AddIns/Misc/MbUnitPad/Project/Src/MbUnitPad.cs
+++ b/src/AddIns/Misc/MbUnitPad/Project/Src/MbUnitPad.cs
@@ -78,6 +78,12 @@ namespace ICSharpCode.MbUnitPad
}
}
+ public string SelectedAssemblyFileName {
+ get {
+ return treeView.SelectedAssemblyFileName;
+ }
+ }
+
void OnSolutionLoaded(object sender, EventArgs e)
{
UpdateToolbar();
diff --git a/src/AddIns/Misc/MbUnitPad/Project/Src/TestTreeView.cs b/src/AddIns/Misc/MbUnitPad/Project/Src/TestTreeView.cs
index bd76ef3004..61ed50d1ee 100644
--- a/src/AddIns/Misc/MbUnitPad/Project/Src/TestTreeView.cs
+++ b/src/AddIns/Misc/MbUnitPad/Project/Src/TestTreeView.cs
@@ -61,6 +61,20 @@ namespace ICSharpCode.MbUnitPad
}
}
+ public string SelectedAssemblyFileName {
+ get {
+ UnitTreeNode node = SelectedNode as UnitTreeNode;
+ if (node != null) {
+ foreach (TreeTestDomain d in this.TestDomains) {
+ if (d.Identifier == node.DomainIdentifier) {
+ return d.TestFilePath;
+ }
+ }
+ }
+ return String.Empty;
+ }
+ }
+
public bool IsPopulated {
get {
return TypeTree.Nodes.Count > 0;
diff --git a/src/Main/StartUp/Project/Resources/BitmapResources.resources b/src/Main/StartUp/Project/Resources/BitmapResources.resources
index e611ece9f7..a407994853 100644
Binary files a/src/Main/StartUp/Project/Resources/BitmapResources.resources and b/src/Main/StartUp/Project/Resources/BitmapResources.resources differ
diff --git a/src/SharpDevelop.sln b/src/SharpDevelop.sln
index d6117812ce..a3b5374d34 100644
--- a/src/SharpDevelop.sln
+++ b/src/SharpDevelop.sln
@@ -1,5 +1,5 @@
Microsoft Visual Studio Solution File, Format Version 9.00
-# SharpDevelop 2.0.0.1020
+# SharpDevelop 2.0.0.960
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AddIns", "AddIns", "{14A277EE-7DF1-4529-B639-7D1EF334C1C5}"
ProjectSection(SolutionItems) = postProject
EndProjectSection
@@ -44,6 +44,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{CE5B42B7-6
ProjectSection(SolutionItems) = postProject
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCoverage", "AddIns\Misc\CodeCoverage\Project\CodeCoverage.csproj", "{08ce9972-283b-44f4-82fa-966f7dfa6b7a}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpQuery", "AddIns\Misc\SharpQuery\SharpQuery.csproj", "{BDD03ECD-42AE-4B50-9805-9C19090A264F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoReflectionLoader", "AddIns\Misc\MonoReflectionLoader\Project\MonoReflectionLoader.csproj", "{8C52FFA5-35AF-4E28-8498-2DC2F168A241}"
@@ -274,6 +276,10 @@ Global
{0F784A65-33B4-43EB-A49A-50A15EEF9829}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0F784A65-33B4-43EB-A49A-50A15EEF9829}.Release|Any CPU.Build.0 = Release|Any CPU
{0F784A65-33B4-43EB-A49A-50A15EEF9829}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {08CE9972-283B-44F4-82FA-966F7DFA6B7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {08CE9972-283B-44F4-82FA-966F7DFA6B7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {08CE9972-283B-44F4-82FA-966F7DFA6B7A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {08CE9972-283B-44F4-82FA-966F7DFA6B7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -309,6 +315,7 @@ Global
{082DCD64-EE32-4151-A50F-E139CF754CC0} = {CE5B42B7-6E8C-4385-9E97-F4023FC16BF2}
{8C52FFA5-35AF-4E28-8498-2DC2F168A241} = {CE5B42B7-6E8C-4385-9E97-F4023FC16BF2}
{BDD03ECD-42AE-4B50-9805-9C19090A264F} = {CE5B42B7-6E8C-4385-9E97-F4023FC16BF2}
+ {08ce9972-283b-44f4-82fa-966f7dfa6b7a} = {CE5B42B7-6E8C-4385-9E97-F4023FC16BF2}
{B08385CD-F0CC-488C-B4F4-EEB34B6D2688} = {6604365C-C702-4C10-9BA8-637F1E3D4D0D}
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8} = {6604365C-C702-4C10-9BA8-637F1E3D4D0D}
{EC06F96A-AEEC-49D6-B03D-AB87C6EB674C} = {6604365C-C702-4C10-9BA8-637F1E3D4D0D}