#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

265 lines
7.2 KiB

// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Specialized;
using System.Text;
using ICSharpCode.SharpDevelop.Util;
namespace ICSharpCode.CodeCoverage
{
/// <summary>
/// Description of PartCoverRunner.
/// </summary>
public class PartCoverRunner
{
ProcessRunner runner;
string partCoverFileName = String.Empty;
string workingDirectory = String.Empty;
string target = String.Empty;
string targetWorkingDirectory = String.Empty;
string targetArguments = String.Empty;
StringCollection include = new StringCollection();
StringCollection exclude = new StringCollection();
string output = String.Empty;
/// <summary>
/// Triggered when PartCover exits.
/// </summary>
public event PartCoverExitEventHandler Exited;
/// <summary>
/// The PartCover runner was started.
/// </summary>
public event EventHandler Started;
/// <summary>
/// The PartCover runner was stopped. Being stopped is not the
/// same as PartCover exiting.
/// </summary>
public event EventHandler Stopped;
/// <summary>
/// Triggered when an output line is received from PartCover.
/// </summary>
public event LineReceivedEventHandler OutputLineReceived;
public PartCoverRunner()
{
}
/// <summary>
/// Gets or sets the full path to the PartCover
/// executable.
/// </summary>
public string PartCoverFileName {
get { return partCoverFileName; }
set { partCoverFileName = value; }
}
/// <summary>
/// Gets or sets the working directory to use when running
/// PartCover.
/// </summary>
public string WorkingDirectory {
get { return workingDirectory; }
set { workingDirectory = value; }
}
/// <summary>
/// Gets or sets the filename of the executable to profile with PartCover.
/// </summary>
public string Target {
get { return target; }
set { target = value; }
}
/// <summary>
/// Gets or sets the working directory for the target executable.
/// </summary>
public string TargetWorkingDirectory {
get { return targetWorkingDirectory; }
set { targetWorkingDirectory = value; }
}
/// <summary>
/// Gets or sets the arguments to pass to the target executable.
/// </summary>
public string TargetArguments {
get { return targetArguments; }
set { targetArguments = value; }
}
/// <summary>
/// Gets or sets the regular expressions which specify the items to
/// include in the report whilst profiling the target executable.
/// </summary>
public StringCollection Include {
get { return include; }
}
/// <summary>
/// Gets or sets the regular expressions which specify the items to
/// exclude in the report whilst profiling the target executable.
/// </summary>
public StringCollection Exclude {
get { return exclude; }
}
/// <summary>
/// Gets or sets the filename for the code coverage results.
/// </summary>
public string Output {
get { return output; }
set { output = value; }
}
/// <summary>
/// Returns the full path used to run PartCover.
/// Includes the path to the PartCover executable
/// and the command line arguments.
/// </summary>
public string CommandLine {
get {
string arguments = GetArguments();
if (arguments.Length > 0) {
return String.Concat(partCoverFileName, " ", arguments);
}
return partCoverFileName;
}
}
/// <summary>
/// Returns the command line arguments used to run PartCover.
/// </summary>
/// <remarks>
/// Note that the target arguments may itself contain double quotes
/// so in order for this to be passed to PartCover as a single argument
/// we need to prefix each double quote by a backslash. For example:
///
/// Target args: "C:\Projects\My Tests\Test.dll" /output "C:\Projects\My Tests\Output.xml"
///
/// PartCover: --target-args "\"C:\Projects\My Tests\Test.dll\" /output \"C:\Projects\My Tests\Output.xml\""
/// </remarks>
public string GetArguments()
{
StringBuilder arguments = new StringBuilder();
if (!String.IsNullOrEmpty(target)) {
arguments.AppendFormat("--target \"{0}\" ", target);
}
if (!String.IsNullOrEmpty(targetWorkingDirectory)) {
arguments.AppendFormat("--target-work-dir \"{0}\" ", targetWorkingDirectory);
}
if (!String.IsNullOrEmpty(targetArguments)) {
arguments.AppendFormat("--target-args \"{0}\" ", targetArguments.Replace("\"", "\\\""));
}
if (!String.IsNullOrEmpty(output)) {
arguments.AppendFormat("--output \"{0}\" ", output);
}
arguments.Append(GetArguments("--include", include));
if (include.Count > 0) {
// Add a space between include and exclude arguments.
arguments.Append(' ');
}
arguments.Append(GetArguments("--exclude", exclude));
return arguments.ToString().Trim();
}
public void Start()
{
string arguments = GetArguments();
runner = new ProcessRunner();
runner.WorkingDirectory = workingDirectory;
runner.ProcessExited += ProcessExited;
if (OutputLineReceived != null) {
runner.OutputLineReceived += OnOutputLineReceived;
runner.ErrorLineReceived += OnOutputLineReceived;
}
runner.Start(partCoverFileName, arguments);
OnStarted();
}
/// <summary>
/// Stops the currently running PartCover instance.
/// </summary>
public void Stop()
{
if (runner != null) {
runner.Kill();
OnStopped();
}
}
protected void OnExited(string output, string error, int exitCode)
{
if (Exited != null) {
Exited(this, new PartCoverExitEventArgs(output, error, exitCode));
}
}
protected void OnStarted()
{
if (Started != null) {
Started(this, new EventArgs());
}
}
protected void OnStopped()
{
if (Stopped != null) {
Stopped(this, new EventArgs());
}
}
/// <summary>
/// Raises the <see cref="OutputLineReceived"/> event.
/// </summary>
/// <param name="sender">The event source.</param>
/// <param name="e">The event arguments.</param>
protected void OnOutputLineReceived(object sender, LineReceivedEventArgs e)
{
if (OutputLineReceived != null) {
OutputLineReceived(this, e);
}
}
/// <summary>
/// Handles the PartCover process exit event.
/// </summary>
/// <param name="sender">The event source.</param>
/// <param name="e">The event arguments.</param>
void ProcessExited(object sender, EventArgs e)
{
ProcessRunner runner = (ProcessRunner)sender;
OnExited(runner.StandardOutput, runner.StandardError, runner.ExitCode);
}
/// <summary>
/// Gets the command line option that can have multiple items as specified
/// in the string array. Each array item will have a separate command line
/// argument (e.g. --include=A --include=B --include=B).
/// </summary>
static string GetArguments(string argumentName, StringCollection items)
{
StringBuilder arguments = new StringBuilder();
foreach (string item in items) {
arguments.Append(argumentName);
arguments.Append(" ");
arguments.Append(item);
arguments.Append(" ");
}
return arguments.ToString().Trim();
}
}
}