Browse Source

Use named pipe instead of temporary file for sending the unit tests results to SharpDevelop.

newNRvisualizers
Daniel Grunwald 13 years ago
parent
commit
81361f7a12
  1. 2
      src/AddIns/Analysis/UnitTesting/Interfaces/IUnitTestProcessRunner.cs
  2. 5
      src/AddIns/Analysis/UnitTesting/Interfaces/UnitTestProcessRunner.cs
  3. 10
      src/AddIns/Analysis/UnitTesting/NUnit/NUnitConsoleApplication.cs
  4. 13
      src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestDebugger.cs
  5. 19
      src/AddIns/Analysis/UnitTesting/NUnit/NUnitTestRunner.cs
  6. 8
      src/AddIns/Analysis/UnitTesting/Test/NUnit/NUnitConsoleCommandLineTests.cs
  7. 93
      src/AddIns/Analysis/UnitTesting/Test/TestRunner/TestResultsReaderTests.cs
  8. 20
      src/AddIns/Analysis/UnitTesting/TestRunner/ITestResultsMonitor.cs
  9. 24
      src/AddIns/Analysis/UnitTesting/TestRunner/TestDebuggerBase.cs
  10. 28
      src/AddIns/Analysis/UnitTesting/TestRunner/TestProcessRunnerBase.cs
  11. 12
      src/AddIns/Analysis/UnitTesting/TestRunner/TestProcessRunnerBaseContext.cs
  12. 178
      src/AddIns/Analysis/UnitTesting/TestRunner/TestResultsMonitor.cs
  13. 122
      src/AddIns/Analysis/UnitTesting/TestRunner/TestResultsReader.cs
  14. 11
      src/AddIns/Analysis/UnitTesting/TestRunner/TestRunnerBase.cs
  15. 4
      src/AddIns/Analysis/UnitTesting/UnitTesting.csproj
  16. 23
      src/Main/Base/Project/Src/Util/ProcessRunner.cs
  17. 2
      src/Tools/NUnit/buildnunitconsole.bat
  18. BIN
      src/Tools/NUnit/nunit-console-dotnet2-x86.exe
  19. BIN
      src/Tools/NUnit/nunit-console-dotnet2.exe
  20. BIN
      src/Tools/NUnit/nunit-console-x86.exe
  21. BIN
      src/Tools/NUnit/nunit-console.exe
  22. 8
      src/Tools/NUnit/nunit-console/ExtendedConsoleOptions.cs
  23. 9
      src/Tools/NUnit/nunit-console/ExtendedConsoleUi.cs
  24. 8
      src/Tools/NUnit/nunit-console/nunit-console.csproj

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

@ -7,7 +7,7 @@ using ICSharpCode.SharpDevelop.Util; @@ -7,7 +7,7 @@ using ICSharpCode.SharpDevelop.Util;
namespace ICSharpCode.UnitTesting
{
public interface IUnitTestProcessRunner
public interface IUnitTestProcessRunner : IDisposable
{
bool LogStandardOutputAndError { get; set; }
string WorkingDirectory { get; set; }

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

@ -54,5 +54,10 @@ namespace ICSharpCode.UnitTesting @@ -54,5 +54,10 @@ namespace ICSharpCode.UnitTesting
{
runner.Kill();
}
public void Dispose()
{
runner.Dispose();
}
}
}

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

@ -141,9 +141,9 @@ namespace ICSharpCode.UnitTesting @@ -141,9 +141,9 @@ namespace ICSharpCode.UnitTesting
public string Test;
/// <summary>
/// File to write test results to.
/// Pipe to write test results to.
/// </summary>
public string Results;
public string ResultsPipe;
/// <summary>
/// The namespace that tests need to be a part of if they are to
@ -206,9 +206,9 @@ namespace ICSharpCode.UnitTesting @@ -206,9 +206,9 @@ namespace ICSharpCode.UnitTesting
b.Append(XmlOutputFile);
b.Append('"');
}
if (Results != null) {
b.Append(" /results=\"");
b.Append(Results);
if (ResultsPipe != null) {
b.Append(" /pipe=\"");
b.Append(ResultsPipe);
b.Append('"');
}
string run = null;

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

@ -18,16 +18,16 @@ namespace ICSharpCode.UnitTesting @@ -18,16 +18,16 @@ namespace ICSharpCode.UnitTesting
public NUnitTestDebugger()
: this(new UnitTestDebuggerService(),
SD.MessageService,
new TestResultsMonitor(),
new TestResultsReader(),
UnitTestingOptions.Instance.Clone())
{
}
public NUnitTestDebugger(IUnitTestDebuggerService debuggerService,
IMessageService messageService,
ITestResultsMonitor testResultsMonitor,
ITestResultsReader testResultsReader,
UnitTestingOptions options)
: base(debuggerService, messageService, testResultsMonitor)
: base(debuggerService, messageService, testResultsReader)
{
this.options = options;
}
@ -35,7 +35,7 @@ namespace ICSharpCode.UnitTesting @@ -35,7 +35,7 @@ namespace ICSharpCode.UnitTesting
protected override ProcessStartInfo GetProcessStartInfo(IEnumerable<ITest> selectedTests)
{
NUnitConsoleApplication app = new NUnitConsoleApplication(selectedTests, options);
app.Results = base.TestResultsMonitor.FileName;
app.ResultsPipe = base.TestResultsReader.PipeName;
return app.GetProcessStartInfo();
}
@ -43,5 +43,10 @@ namespace ICSharpCode.UnitTesting @@ -43,5 +43,10 @@ namespace ICSharpCode.UnitTesting
{
return new NUnitTestResult(testResult);
}
public override int GetExpectedNumberOfTestResults(IEnumerable<ITest> selectedTests)
{
return NUnitTestRunner.GetNumberOfTestMethods(selectedTests);
}
}
}

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

@ -30,7 +30,7 @@ namespace ICSharpCode.UnitTesting @@ -30,7 +30,7 @@ namespace ICSharpCode.UnitTesting
protected override ProcessStartInfo GetProcessStartInfo(IEnumerable<ITest> selectedTests)
{
NUnitConsoleApplication app = new NUnitConsoleApplication(selectedTests, options);
app.Results = base.TestResultsMonitor.FileName;
app.ResultsPipe = base.TestResultsReader.PipeName;
return app.GetProcessStartInfo();
}
@ -38,5 +38,22 @@ namespace ICSharpCode.UnitTesting @@ -38,5 +38,22 @@ namespace ICSharpCode.UnitTesting
{
return new NUnitTestResult(testResult);
}
public override int GetExpectedNumberOfTestResults(IEnumerable<ITest> selectedTests)
{
return GetNumberOfTestMethods(selectedTests);
}
public static int GetNumberOfTestMethods(IEnumerable<ITest> selectedTests)
{
int count = 0;
foreach (ITest test in selectedTests) {
if (test is NUnitTestMethod)
count++;
else
count += GetNumberOfTestMethods(test.NestedTests);
}
return count;
}
}
}

8
src/AddIns/Analysis/UnitTesting/Test/NUnit/NUnitConsoleCommandLineTests.cs

@ -38,9 +38,9 @@ namespace UnitTesting.Tests.NUnit @@ -38,9 +38,9 @@ namespace UnitTesting.Tests.NUnit
app.NoLogo = false;
app.ShadowCopy = true;
app.NoXmlOutputFile = false;
app.Results = @"C:\results.txt";
app.ResultsPipe = @"C:\results.txt";
string expectedCommandLine = "\"C:\\Projects\\MyTests\\MyTests.dll\" /results=\"C:\\results.txt\"";
string expectedCommandLine = "\"C:\\Projects\\MyTests\\MyTests.dll\" /pipe=\"C:\\results.txt\"";
Assert.AreEqual(expectedCommandLine, app.GetArguments());
}
@ -229,13 +229,13 @@ namespace UnitTesting.Tests.NUnit @@ -229,13 +229,13 @@ namespace UnitTesting.Tests.NUnit
app.Assemblies.Add("SecondAssembly.dll");
app.NoLogo = false;
app.ShadowCopy = true;
app.Results = @"C:\results.txt";
app.ResultsPipe = @"C:\results.txt";
app.NoXmlOutputFile = false;
string expectedCommandLine =
"\"C:\\Projects\\MyTests\\MyTests.dll\" " +
"\"SecondAssembly.dll\" " +
"/results=\"C:\\results.txt\"";
"/pipe=\"C:\\results.txt\"";
Assert.AreEqual(expectedCommandLine, app.GetArguments());
}

93
src/AddIns/Analysis/UnitTesting/Test/TestRunner/TestResultsReaderTests.cs

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using ICSharpCode.UnitTesting;
using NUnit.Framework;
@ -17,10 +18,12 @@ namespace UnitTesting.Tests.TestRunner @@ -17,10 +18,12 @@ namespace UnitTesting.Tests.TestRunner
string resultsText = "Name: MyTest\r\n" +
"Result: Success\r\n";
TestResultsReader reader = new TestResultsReader();
TestResult[] results = reader.Read(resultsText);
TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(1, results.Length);
Assert.AreEqual(1, results.Count);
TestResult result = results[0];
Assert.AreEqual("MyTest", result.Name);
@ -34,10 +37,12 @@ namespace UnitTesting.Tests.TestRunner @@ -34,10 +37,12 @@ namespace UnitTesting.Tests.TestRunner
string resultsText = "Name: MyTest\r\n" +
"Result: Ignored\r\n";
TestResultsReader reader = new TestResultsReader();
TestResult[] results = reader.Read(resultsText);
TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(1, results.Length);
Assert.AreEqual(1, results.Count);
TestResult result = results[0];
Assert.AreEqual("MyTest", result.Name);
@ -45,7 +50,7 @@ namespace UnitTesting.Tests.TestRunner @@ -45,7 +50,7 @@ namespace UnitTesting.Tests.TestRunner
Assert.IsFalse(result.IsSuccess);
Assert.AreEqual(TestResultType.Ignored, result.ResultType);
}
/*
[Test]
public void OneTestPassInParts()
{
@ -70,17 +75,19 @@ namespace UnitTesting.Tests.TestRunner @@ -70,17 +75,19 @@ namespace UnitTesting.Tests.TestRunner
Assert.AreEqual("MyTest", result.Name);
Assert.IsTrue(result.IsSuccess);
}
*/
[Test]
public void OneTestFailure()
{
string resultsText = "Name: MyTest\r\n" +
"Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader();
TestResult[] results = reader.Read(resultsText);
TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(1, results.Length);
Assert.AreEqual(1, results.Count);
TestResult result = results[0];
Assert.AreEqual("MyTest", result.Name);
@ -97,10 +104,12 @@ namespace UnitTesting.Tests.TestRunner @@ -97,10 +104,12 @@ namespace UnitTesting.Tests.TestRunner
"Message: Should not be 0.\r\n" +
"Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader();
TestResult[] results = reader.Read(resultsText);
TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(1, results.Length);
Assert.AreEqual(1, results.Count);
TestResult result = results[0];
Assert.AreEqual("Test", result.Name);
@ -115,10 +124,12 @@ namespace UnitTesting.Tests.TestRunner @@ -115,10 +124,12 @@ namespace UnitTesting.Tests.TestRunner
"StackTrace: stack trace\r\n" +
"Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader();
TestResult[] results = reader.Read(resultsText);
TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(1, results.Length);
Assert.AreEqual(1, results.Count);
TestResult result = results[0];
Assert.AreEqual("Test", result.Name);
@ -131,10 +142,12 @@ namespace UnitTesting.Tests.TestRunner @@ -131,10 +142,12 @@ namespace UnitTesting.Tests.TestRunner
{
string resultsText = "Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader();
TestResult[] results = reader.Read(resultsText);
TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(0, results.Length);
Assert.AreEqual(0, results.Count);
}
[Test]
@ -144,10 +157,12 @@ namespace UnitTesting.Tests.TestRunner @@ -144,10 +157,12 @@ namespace UnitTesting.Tests.TestRunner
"Name: Test\r\n" +
"Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader();
TestResult[] results = reader.Read(resultsText);
TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(1, results.Length);
Assert.AreEqual(1, results.Count);
TestResult result = results[0];
Assert.AreEqual("Test", result.Name);
@ -162,10 +177,12 @@ namespace UnitTesting.Tests.TestRunner @@ -162,10 +177,12 @@ namespace UnitTesting.Tests.TestRunner
" Should be 1.\r\n" +
"Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader();
TestResult[] results = reader.Read(resultsText);
TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(1, results.Length);
Assert.AreEqual(1, results.Count);
TestResult result = results[0];
Assert.AreEqual("Test", result.Name);
@ -182,10 +199,12 @@ namespace UnitTesting.Tests.TestRunner @@ -182,10 +199,12 @@ namespace UnitTesting.Tests.TestRunner
" End of message.\r\n" +
"Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader();
TestResult[] results = reader.Read(resultsText);
TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(1, results.Length);
Assert.AreEqual(1, results.Count);
TestResult result = results[0];
Assert.AreEqual("Test", result.Name);
@ -201,10 +220,12 @@ namespace UnitTesting.Tests.TestRunner @@ -201,10 +220,12 @@ namespace UnitTesting.Tests.TestRunner
"Name: MyTest2\r\n" +
"Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader();
TestResult[] results = reader.Read(resultsText);
TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(2, results.Length);
Assert.AreEqual(2, results.Count);
TestResult result1 = results[0];
Assert.AreEqual("MyTest1", result1.Name);
@ -228,10 +249,12 @@ namespace UnitTesting.Tests.TestRunner @@ -228,10 +249,12 @@ namespace UnitTesting.Tests.TestRunner
" ThirdLine\r\n" +
"Result: Failure\r\n";
TestResultsReader reader = new TestResultsReader();
TestResult[] results = reader.Read(resultsText);
TestResultsReader reader = new TestResultsReader(new StringReader(resultsText));
List<TestResult> results = new List<TestResult>();
reader.TestFinished += (sender, e) => results.Add(e.Result);
reader.Run();
Assert.AreEqual(2, results.Length);
Assert.AreEqual(2, results.Count);
TestResult result1 = results[0];
Assert.AreEqual("MyTest1", result1.Name);

20
src/AddIns/Analysis/UnitTesting/TestRunner/ITestResultsMonitor.cs

@ -1,20 +0,0 @@ @@ -1,20 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
namespace ICSharpCode.UnitTesting
{
public interface ITestResultsMonitor : IDisposable
{
event EventHandler<TestFinishedEventArgs> TestFinished;
string FileName { get; set; }
void Stop();
void Start();
void Read();
long InitialFilePosition { get; set; }
}
}

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

@ -16,29 +16,29 @@ namespace ICSharpCode.UnitTesting @@ -16,29 +16,29 @@ namespace ICSharpCode.UnitTesting
IUnitTestDebuggerService debuggerService;
IMessageService messageService;
IDebugger debugger;
ITestResultsMonitor testResultsMonitor;
ITestResultsReader testResultsReader;
public TestDebuggerBase()
: this(new UnitTestDebuggerService(),
SD.MessageService,
new TestResultsMonitor())
new TestResultsReader())
{
}
public TestDebuggerBase(IUnitTestDebuggerService debuggerService,
IMessageService messageService,
ITestResultsMonitor testResultsMonitor)
ITestResultsReader testResultsReader)
{
this.debuggerService = debuggerService;
this.messageService = messageService;
this.testResultsMonitor = testResultsMonitor;
this.testResultsReader = testResultsReader;
this.debugger = debuggerService.CurrentDebugger;
testResultsMonitor.TestFinished += OnTestFinished;
testResultsReader.TestFinished += OnTestFinished;
}
protected ITestResultsMonitor TestResultsMonitor {
get { return testResultsMonitor; }
protected ITestResultsReader TestResultsReader {
get { return testResultsReader; }
}
public override void Start(IEnumerable<ITest> selectedTests)
@ -67,7 +67,7 @@ namespace ICSharpCode.UnitTesting @@ -67,7 +67,7 @@ namespace ICSharpCode.UnitTesting
void Start(ProcessStartInfo startInfo)
{
testResultsMonitor.Start();
testResultsReader.Start();
StartDebugger(startInfo);
}
@ -90,6 +90,7 @@ namespace ICSharpCode.UnitTesting @@ -90,6 +90,7 @@ namespace ICSharpCode.UnitTesting
void DebugStopped(object source, EventArgs e)
{
debugger.DebugStopped -= DebugStopped;
testResultsReader.Join();
OnAllTestsFinished(source, e);
}
@ -98,15 +99,12 @@ namespace ICSharpCode.UnitTesting @@ -98,15 +99,12 @@ namespace ICSharpCode.UnitTesting
if (debugger.IsDebugging) {
debugger.Stop();
}
testResultsMonitor.Stop();
testResultsMonitor.Read();
}
public override void Dispose()
{
Stop();
testResultsMonitor.Dispose();
testResultsReader.Dispose();
testResultsReader.TestFinished -= OnTestFinished;
}
}
}

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

@ -11,17 +11,17 @@ using ICSharpCode.SharpDevelop.Util; @@ -11,17 +11,17 @@ using ICSharpCode.SharpDevelop.Util;
namespace ICSharpCode.UnitTesting
{
public class TestProcessRunnerBase : TestRunnerBase
public abstract class TestProcessRunnerBase : TestRunnerBase
{
IUnitTestProcessRunner processRunner;
ITestResultsMonitor testResultsMonitor;
ITestResultsReader testResultsReader;
IFileSystem fileSystem;
IMessageService messageService;
public TestProcessRunnerBase(TestProcessRunnerBaseContext context)
{
this.processRunner = context.TestProcessRunner;
this.testResultsMonitor = context.TestResultsMonitor;
this.testResultsReader = context.TestResultsReader;
this.fileSystem = context.FileSystem;
this.messageService = context.MessageService;
@ -29,11 +29,11 @@ namespace ICSharpCode.UnitTesting @@ -29,11 +29,11 @@ namespace ICSharpCode.UnitTesting
processRunner.OutputLineReceived += OutputLineReceived;
processRunner.ErrorLineReceived += OutputLineReceived;
processRunner.ProcessExited += OnAllTestsFinished;
testResultsMonitor.TestFinished += OnTestFinished;
testResultsReader.TestFinished += OnTestFinished;
}
protected ITestResultsMonitor TestResultsMonitor {
get { return testResultsMonitor; }
protected ITestResultsReader TestResultsReader {
get { return testResultsReader; }
}
protected IUnitTestProcessRunner ProcessRunner {
@ -56,7 +56,7 @@ namespace ICSharpCode.UnitTesting @@ -56,7 +56,7 @@ namespace ICSharpCode.UnitTesting
LogCommandLine(processStartInfo);
if (ApplicationFileNameExists(processStartInfo.FileName)) {
testResultsMonitor.Start();
testResultsReader.Start();
processRunner.WorkingDirectory = processStartInfo.WorkingDirectory;
processRunner.Start(processStartInfo.FileName, processStartInfo.Arguments);
} else {
@ -75,17 +75,23 @@ namespace ICSharpCode.UnitTesting @@ -75,17 +75,23 @@ namespace ICSharpCode.UnitTesting
messageService.ShowErrorFormatted(resourceString, fileName);
}
protected override void OnAllTestsFinished(object source, EventArgs e)
{
testResultsReader.Join();
base.OnAllTestsFinished(source, e);
}
public override void Stop()
{
SD.Log.Info("Killing unit test runner");
processRunner.Kill();
testResultsMonitor.Stop();
testResultsMonitor.Read();
}
public override void Dispose()
{
testResultsMonitor.Dispose();
testResultsMonitor.TestFinished -= OnTestFinished;
processRunner.Dispose();
testResultsReader.Dispose();
testResultsReader.TestFinished -= OnTestFinished;
processRunner.ErrorLineReceived -= OutputLineReceived;
processRunner.OutputLineReceived -= OutputLineReceived;
}

12
src/AddIns/Analysis/UnitTesting/TestRunner/TestProcessRunnerBaseContext.cs

@ -11,25 +11,25 @@ namespace ICSharpCode.UnitTesting @@ -11,25 +11,25 @@ namespace ICSharpCode.UnitTesting
public class TestProcessRunnerBaseContext
{
IUnitTestProcessRunner processRunner;
ITestResultsMonitor testResultsMonitor;
ITestResultsReader testResultsReader;
IFileSystem fileSystem;
IMessageService messageService;
public TestProcessRunnerBaseContext()
: this(new UnitTestProcessRunner(),
new TestResultsMonitor(),
new TestResultsReader(),
new UnitTestFileService(),
SD.MessageService)
{
}
public TestProcessRunnerBaseContext(IUnitTestProcessRunner processRunner,
ITestResultsMonitor testResultsMonitor,
ITestResultsReader testResultsMonitor,
IFileSystem fileSystem,
IMessageService messageService)
{
this.processRunner = processRunner;
this.testResultsMonitor = testResultsMonitor;
this.testResultsReader = testResultsMonitor;
this.fileSystem = fileSystem;
this.messageService = messageService;
}
@ -38,8 +38,8 @@ namespace ICSharpCode.UnitTesting @@ -38,8 +38,8 @@ namespace ICSharpCode.UnitTesting
get { return processRunner; }
}
public ITestResultsMonitor TestResultsMonitor {
get { return testResultsMonitor; }
public ITestResultsReader TestResultsReader {
get { return testResultsReader; }
}
public IFileSystem FileSystem {

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

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

122
src/AddIns/Analysis/UnitTesting/TestRunner/TestResultsReader.cs

@ -2,52 +2,118 @@ @@ -2,52 +2,118 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
namespace ICSharpCode.UnitTesting
{
/// <summary>
/// Reads the test results file produced by the custom
/// nunit-console application.
/// </summary>
public class TestResultsReader
public interface ITestResultsReader : IDisposable
{
StringBuilder nameBuilder = new StringBuilder();
StringBuilder valueBuilder = new StringBuilder();
bool firstNameChar = true;
TestResult result;
event EventHandler<TestFinishedEventArgs> TestFinished;
string PipeName { get; }
void Start();
void Join();
}
public class TestResultsReader : ITestResultsReader
{
TextReader reader;
readonly NamedPipeServerStream namedPipe;
readonly string pipeName;
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
enum State {
WaitingForEndOfName = 0,
WaitingForStartOfValue = 1,
WaitingForEndOfValue = 2
public TestResultsReader()
{
pipeName = Guid.NewGuid().ToString();
namedPipe = new NamedPipeServerStream(this.PipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte);
}
State state = State.WaitingForEndOfName;
/// <summary>
/// Creates a new TestResultsReader that reads from an existing text reader.
/// </summary>
public TestResultsReader(TextReader reader)
{
this.reader = reader;
}
public TestResultsReader()
public string PipeName {
get { return pipeName; }
}
public void Dispose()
{
reader.Dispose();
namedPipe.Dispose();
}
public event EventHandler<TestFinishedEventArgs> TestFinished;
Thread thread;
/// <summary>
/// Runs the pipe reader on a background thread.
/// The returned task will be signalled as completed when the worker process closes the pipe, after
/// all contents have been read from the pipe.
/// </summary>
public void Start()
{
thread = new Thread(Run);
thread.Name = "UnitTesting Pipe Reader";
thread.Start();
}
public void Join()
{
SD.Log.Debug("Waiting for pipe reader to finish");
thread.Join();
SD.Log.Debug("Pipe reader has finished");
}
/// <summary>
/// Returns any TestResults that are in the text.
/// Run the pipe reader on the current thread.
/// This method blocks until the worker process closes the pipe.
/// </summary>
/// <param name="text">The text read in from the
/// TestResults file.</param>
public TestResult[] Read(string text)
public void Run()
{
List<TestResult> results = new List<TestResult>();
foreach (char ch in text) {
if (ReadNameValuePair(ch)) {
if (ReadTestResult()) {
results.Add(result);
if (reader == null) {
SD.Log.Debug("Waiting for connection to pipe");
namedPipe.WaitForConnection();
SD.Log.Debug("Start reading pipe");
reader = new StreamReader(namedPipe);
}
char[] buffer = new char[1024];
int read;
while ((read = reader.Read(buffer, 0, buffer.Length)) != 0) {
for (int i = 0; i < read; i++) {
if (ReadNameValuePair(buffer[i])) {
if (ReadTestResult()) {
if (TestFinished != null)
TestFinished(this, new TestFinishedEventArgs(result));
}
}
}
}
return results.ToArray();
SD.Log.Debug("End of pipe");
}
StringBuilder nameBuilder = new StringBuilder();
StringBuilder valueBuilder = new StringBuilder();
bool firstNameChar = true;
TestResult result;
enum State {
WaitingForEndOfName = 0,
WaitingForStartOfValue = 1,
WaitingForEndOfValue = 2
}
State state = State.WaitingForEndOfName;
/// <summary>
/// Reads a name-value pair of the form:
///
@ -119,8 +185,8 @@ namespace ICSharpCode.UnitTesting @@ -119,8 +185,8 @@ namespace ICSharpCode.UnitTesting
/// <returns>True if a TestResult is ready to be returned
/// to the caller.</returns>
/// <remarks>
/// The first name-value pair for a test result is the
/// test name. The last name-value pair is the result of
/// The first name-value pair for a test result is the
/// test name. The last name-value pair is the result of
/// the test (Success, Failure or Ignored).</remarks>
bool ReadTestResult()
{

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

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -11,12 +12,17 @@ namespace ICSharpCode.UnitTesting @@ -11,12 +12,17 @@ namespace ICSharpCode.UnitTesting
{
public abstract class TestRunnerBase : ITestRunner
{
IProgress<double> progress;
double progressPerTest;
int testsFinished;
TaskCompletionSource<object> tcs;
CancellationTokenRegistration cancellationTokenRegistration;
bool wasCancelled;
public Task RunAsync(IEnumerable<ITest> selectedTests, IProgress<double> progress, CancellationToken cancellationToken)
{
this.progress = progress;
progressPerTest = 1.0 / GetExpectedNumberOfTestResults(selectedTests);
tcs = new TaskCompletionSource<object>();
Start(selectedTests);
cancellationTokenRegistration = cancellationToken.Register(Cancel, true);
@ -45,7 +51,7 @@ namespace ICSharpCode.UnitTesting @@ -45,7 +51,7 @@ namespace ICSharpCode.UnitTesting
return String.Format("\"{0}\" {1}", startInfo.FileName, startInfo.Arguments);
}
protected void OnAllTestsFinished(object source, EventArgs e)
protected virtual void OnAllTestsFinished(object source, EventArgs e)
{
cancellationTokenRegistration.Dispose();
if (wasCancelled)
@ -62,6 +68,8 @@ namespace ICSharpCode.UnitTesting @@ -62,6 +68,8 @@ namespace ICSharpCode.UnitTesting
TestResult testResult = CreateTestResultForTestFramework(e.Result);
TestFinished(source, new TestFinishedEventArgs(testResult));
}
if (!double.IsInfinity(progressPerTest))
progress.Report(progressPerTest * Interlocked.Increment(ref testsFinished));
}
protected virtual TestResult CreateTestResultForTestFramework(TestResult testResult)
@ -78,6 +86,7 @@ namespace ICSharpCode.UnitTesting @@ -78,6 +86,7 @@ namespace ICSharpCode.UnitTesting
}
}
public abstract int GetExpectedNumberOfTestResults(IEnumerable<ITest> selectedTests);
public abstract void Dispose();
public abstract void Stop();
public abstract void Start(IEnumerable<ITest> selectedTests);

4
src/AddIns/Analysis/UnitTesting/UnitTesting.csproj

@ -107,17 +107,15 @@ @@ -107,17 +107,15 @@
<Compile Include="Service\TestFrameworkDescriptor.cs" />
<Compile Include="Service\TestFrameworkDoozer.cs" />
<Compile Include="Service\SDTestService.cs" />
<Compile Include="TestRunner\ITestResultsMonitor.cs" />
<Compile Include="TestRunner\ITestRunner.cs" />
<Compile Include="TestRunner\MessageReceivedEventArgs.cs" />
<Compile Include="TestRunner\TestDebuggerBase.cs" />
<Compile Include="TestRunner\TestExecutionManager.cs" />
<Compile Include="TestRunner\TestExecutionOptions.cs" />
<Compile Include="TestRunner\TestFinishedEventArgs.cs" />
<Compile Include="TestRunner\TestResultsReader.cs" />
<Compile Include="TestRunner\TestProcessRunnerBase.cs" />
<Compile Include="TestRunner\TestProcessRunnerBaseContext.cs" />
<Compile Include="TestRunner\TestResultsMonitor.cs" />
<Compile Include="TestRunner\TestResultsReader.cs" />
<Compile Include="TestRunner\TestResultTask.cs" />
<Compile Include="TestRunner\TestRunnerBase.cs" />
<Compile Include="NUnit\NUnitConsoleApplication.cs" />

23
src/Main/Base/Project/Src/Util/ProcessRunner.cs

@ -26,7 +26,7 @@ namespace ICSharpCode.SharpDevelop.Util @@ -26,7 +26,7 @@ namespace ICSharpCode.SharpDevelop.Util
Process process;
StringBuilder standardOutput = new StringBuilder();
StringBuilder standardError = new StringBuilder();
ManualResetEvent endOfOutput = new ManualResetEvent(false);
ManualResetEventSlim endOfOutput = new ManualResetEventSlim(false);
int outputStreamsFinished;
/// <summary>
@ -91,7 +91,7 @@ namespace ICSharpCode.SharpDevelop.Util @@ -91,7 +91,7 @@ namespace ICSharpCode.SharpDevelop.Util
public void Dispose()
{
process.Dispose();
endOfOutput.Close();
endOfOutput.Dispose();
}
/// <summary>
@ -130,7 +130,7 @@ namespace ICSharpCode.SharpDevelop.Util @@ -130,7 +130,7 @@ namespace ICSharpCode.SharpDevelop.Util
bool exited = process.WaitForExit(timeout);
if (exited) {
endOfOutput.WaitOne(timeout == int.MaxValue ? Timeout.Infinite : timeout, false);
endOfOutput.Wait(timeout == int.MaxValue ? Timeout.Infinite : timeout);
}
return exited;
@ -216,14 +216,15 @@ namespace ICSharpCode.SharpDevelop.Util @@ -216,14 +216,15 @@ namespace ICSharpCode.SharpDevelop.Util
{
if (process != null) {
if (!process.HasExited) {
process.Kill();
process.Close();
process.Dispose();
process = null;
endOfOutput.WaitOne();
} else {
process = null;
try {
process.Kill();
} catch (InvalidOperationException) {
// race condition (if the process has already exited)
}
// don't call process.Dispose() here - that causes the OnProcessExited
// event not to fire correctly
}
endOfOutput.Wait();
}
}
@ -234,7 +235,7 @@ namespace ICSharpCode.SharpDevelop.Util @@ -234,7 +235,7 @@ namespace ICSharpCode.SharpDevelop.Util
{
if (ProcessExited != null) {
if (endOfOutput != null) {
endOfOutput.WaitOne();
endOfOutput.Wait();
}
ProcessExited(this, e);

2
src/Tools/NUnit/buildnunitconsole.bat

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
%windir%\microsoft.net\framework\v4.0.30319\msbuild /Target:Rebuild /property:Configuration=Release nunit-console\nunit-console.sln
copy nunit-console.exe nunit-console-x86.exe
corflags /32bit+ nunit-console-x86.exe
"C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\corflags" /32bit+ nunit-console-x86.exe
@IF %ERRORLEVEL% NEQ 0 GOTO err
copy nunit-console.exe nunit-console-dotnet2.exe
copy nunit-console-x86.exe nunit-console-dotnet2-x86.exe

BIN
src/Tools/NUnit/nunit-console-dotnet2-x86.exe

Binary file not shown.

BIN
src/Tools/NUnit/nunit-console-dotnet2.exe

Binary file not shown.

BIN
src/Tools/NUnit/nunit-console-x86.exe

Binary file not shown.

BIN
src/Tools/NUnit/nunit-console.exe

Binary file not shown.

8
src/Tools/NUnit/nunit-console/ExtendedConsoleOptions.cs

@ -14,14 +14,14 @@ namespace NUnit.ConsoleRunner @@ -14,14 +14,14 @@ namespace NUnit.ConsoleRunner
{
public ExtendedConsoleOptions(string[] args) : base(args) {}
[Option(Description="File to receive test results as each test is run")]
public string results;
[Option(Description="Named pipe to receive test results as each test is run")]
public string pipe;
public bool IsResults
public bool UsePipe
{
get
{
return (results != null) && (results.Length != 0);
return !string.IsNullOrEmpty(pipe);
}
}
}

9
src/Tools/NUnit/nunit-console/ExtendedConsoleUi.cs

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
using System.IO.Pipes;
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
@ -64,9 +65,11 @@ namespace NUnit.ConsoleRunner @@ -64,9 +65,11 @@ namespace NUnit.ConsoleRunner
}
TextWriter testResultWriter = null;
if ( options.IsResults )
if ( options.UsePipe )
{
testResultWriter = new StreamWriter ( options.results, false, Encoding.UTF8 );
var namedPipe = new NamedPipeClientStream(".", options.pipe, PipeDirection.Out, PipeOptions.WriteThrough);
namedPipe.Connect();
testResultWriter = new StreamWriter ( namedPipe, Encoding.UTF8 );
((StreamWriter)testResultWriter).AutoFlush = true;
}
TestPackage package = MakeTestPackage(options);
@ -184,7 +187,7 @@ namespace NUnit.ConsoleRunner @@ -184,7 +187,7 @@ namespace NUnit.ConsoleRunner
outWriter.Close();
if ( redirectError )
errorWriter.Close();
if ( options.IsResults )
if ( testResultWriter != null )
testResultWriter.Close();
Environment.CurrentDirectory = savedDirectory;

8
src/Tools/NUnit/nunit-console/nunit-console.csproj

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<OutputType>Exe</OutputType>
<RootNamespace>NUnit.ConsoleRunner</RootNamespace>
@ -14,7 +15,7 @@ @@ -14,7 +15,7 @@
<FileAlignment>512</FileAlignment>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<ApplicationIcon>App.ico</ApplicationIcon>
<SourceAnalysisOverrideSettingsFile>C:\Users\matt\AppData\Roaming\ICSharpCode/SharpDevelop3.0\Settings.SourceAnalysis</SourceAnalysisOverrideSettingsFile>
</PropertyGroup>
@ -54,6 +55,9 @@ @@ -54,6 +55,9 @@
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Xml" />

Loading…
Cancel
Save